packages feed

cherry-core-alpha-0.1.0.0: src/Tuple.hs

{-|

Module      : Tuples
Description : Work with several values without creating a new data structure.
License     : BSD 3
Maintainer  : terezasokol@gmail.com
Stability   : experimental
Portability : POSIX

There is built-in syntax for tuples, so you can define 2D points like this:

 >  origin :: (Float, Float)
 >  origin =
 >    (0, 0)
 >
 >  position :: (Float, Float)
 >  position =
 >    (3, 4)

This module is a bunch of helpers for working with 2-tuples.

Note 1: For more complex data, it is best to switch to records. So instead
of representing a 3D point as `(3,4,5)` and not having any helper functions,
represent it as `{ x = 3, y = 4, z = 5 }` and use all the built-in record
syntax!

Note 2: If your record contains a bunch of `Bool` and `Maybe` values,
you may want to upgrade to union types. Check out [Joël’s post](https://robots.thoughtbot.com/modeling-with-union-types) for more
info on this.

-}

module Tuple
  ( -- * Create
    pair
    -- * Access
  , first, second
    -- * Map
  , mapFirst, mapSecond, mapBoth
  )
where


-- CREATE


{-| Create a 2-tuple.

  >  -- pair 3 4 == (3, 4)
  >
  >  zip :: List a -> List b -> List (a, b)
  >  zip xs ys =
  >    List.map2 Tuple.pair xs ys
-}
pair :: a -> b -> (a, b)
pair a b =
  (a, b)



-- ACCESS


{-| Extract the first value from a tuple.

  >  first (3, 4) == 3
  >  first ("john", "doe") == "john"
-}
first :: (a, b) -> a
first (x, _) =
  x


{-| Extract the second value from a tuple.

  >  second (3, 4) == 4
  >  second ("john", "doe") == "doe"

-}
second :: (a, b) -> b
second (_, y) =
  y



-- MAP


{-| Transform the first value in a tuple.

  >  import String
  >
  >  mapFirst String.reverse ("stressed", 16) == ("desserts", 16)
  >  mapFirst String.length  ("stressed", 16) == (8, 16)

-}
mapFirst :: (a -> x) -> (a, b) -> (x, b)
mapFirst func (x, y) =
  (func x, y)


{-| Transform the second value in a tuple.

  >  mapSecond sqrt   ("stressed", 16) == ("stressed", 4)
  >  mapSecond negate ("stressed", 16) == ("stressed", -16)

-}
mapSecond :: (b -> y) -> (a, b) -> (a, y)
mapSecond func (x, y) =
  (x, func y)


{-| Transform both parts of a tuple.

  >  import String
  >
  >  mapBoth String.reverse sqrt  ("stressed", 16) == ("desserts", 4)
  >  mapBoth String.length negate ("stressed", 16) == (8, -16)
-}
mapBoth :: (a -> x) -> (b -> y) -> (a, b) -> (x, y)
mapBoth funcA funcB (x, y) =
  (funcA x, funcB y)