{- |
    Overture is an alternative to some of the "Prelude". It borrows ideas from
    <http://elm-lang.org Elm> and <http://fsharp.org F#>. It aims to provide a
    more readable set of functions in order to make Haskell easier to use.

    Overture does not export anything that conflicts with the "Prelude". To
    use it, simply import it.

    >>> import Overture
-}
module Overture where

-- * Identity function

{- |
    <https://en.wikipedia.org/wiki/Identity_function Identity function>.

    Use this function to always return the value it was given.

    >>> identity True
    True

    This is useful when constructing a function that returns another function.

    >>> let f x = if even x then recip else identity
    >>> f 2 10
    0.1
    >>> f 3 10
    10.0

    This is like the 'id' function from the "Prelude".
-}
identity :: a -> a
identity x = x

-- * Constant function

{- |
    <https://en.wikipedia.org/wiki/Constant_function Constant function>.

    Use this function to always return some value, regardless of what the
    other argument is.

    >>> always True False
    True

    This can be useful with higher-order functions. For example, this creates
    a list of three @True@s.

    >>> map (always True) [1 .. 3]
    [True,True,True]

    This is like the 'const' function from the "Prelude".
-}
always :: a -> b -> a
always x _ = x

-- * Function composition

{- |
    <https://en.wikipedia.org/wiki/Function_composition Function composition>.

    Use this function to combine two other functions. The result of
    @'compose' f g@ will be a new function that first applies @f@ and then
    applies @g@. In other words, @'compose' f g x@ is the same as @g (f x)@.
    For instance, the following example will first add one and then multiply
    by two.

    >>> let f = compose (+ 1) (* 2)
    >>> f 3
    8

    You can compose many functions together, but it quickly becomes unwieldy.
    This example does what the previous one did and then cubes the result.

    >>> let g = compose (compose (+ 1) (* 2)) (^ 3)
    >>> g 3
    512

    This is like the function form of the '.' operator from the "Prelude".
-}
compose :: (a -> b) -> (b -> c) -> (a -> c)
compose f g = \ x -> g (f x)

{- |
    Left-associative 'compose' operator.

    Use this operator to combine two other functions in a more natural way
    than with 'compose'. The result of @f '.>' g@ will be a new function that
    first applies @f@ and then applies @g@. Here is the same example from
    above rewritten using this operator.

    >>> let f = (+ 1) .> (* 2)
    >>> f 3
    8

    When reading code, it is useful to pronounce this operator as "and then".
    So the above example could be read as: Add one, /and then/ multiply by
    two".

    When composing many functions, it's easier to use this operator than
    'compose'. Compare this with the earlier example.

    >>> let g = (+ 1) .> (* 2) .> (^ 3)
    >>> g 3
    512

    This is like a flipped version of '.' operator from the "Prelude".
-}
infixl 9 .>
(.>) :: (a -> b) -> (b -> c) -> (a -> c)
f .> g = compose f g

{- |
    Right-associative 'compose' operator.

    Sometimes it is more convenient to combine functions in the opposite
    direction as '.>'. The result of @g '<.' f@ will be a new function that
    applies @g@ but first applies @f@. Here is the same example from before
    rewritten again.

    >>> let f = (* 2) <. (+ 1)
    >>> f 3
    8

    When reading code, it is useful to pronounce this operator as "but first".
    So the above example could be read as: "Multiply by two, /but first/ add
    one".

    Using this operator also leads to more readable code than using 'compose'
    with many functions.

    >>> let g = (^ 3) <. (* 2) <. (+ 1)
    >>> g 3
    512

    This is like the '.' operator from the "Prelude".
-}
infixr 9 <.
(<.) :: (b -> c) -> (a -> b) -> (a -> c)
g <. f = compose f g

-- * Function application

{- |
    <https://en.wikipedia.org/wiki/Function_application Function application>.

    This function isn't usually necessary since @'apply' x f@ is the same as
    @f x@.

    >>> apply (apply 3 (+ 1)) (* 2)
    8

    However it can come in handy when working with higher-order functions.

    >>> map (apply 3) [(+ 1), (* 2)]
    [4,6]

    This is like the '$' operator from the "Prelude".
-}
apply :: a -> (a -> b) -> b
apply x f = f x

{- |
    Left-associative 'apply' operator.

    Since this operator has such low precedence, it can be used to remove
    parentheses in complicated expressions.

    >>> 3 |> (+ 1) |> (* 2)
    8

    When reading code, it is useful to pronounce this operator as "pipe into".
    So the above example can be read as: "Three /piped into/ plus one,
    /piped into/ times two".

    It can also be used with higher-order functions, although 'apply' might be
    clearer.

    >>> map (3 |>) [(+ 1), (* 2)]
    [4,6]

    This is like a flipped version of the '$' operator from the "Prelude".
-}
infixl 0 |>
(|>) :: a -> (a -> b) -> b
x |> f = apply x f

{- |
    Right-associative 'apply' operator.

    Like '|>', this operator also has low precedence. Use it to remove
    parentheses.

    >>> (* 2) <| (+ 1) <| 3
    8

    When reading code, it is useful to pronounce this operator as "pipe from".
    So the above example can be read as: "Times two /piped from/ plus one,
    /piped from/ 3".

    With higher-order functions, it can be a convenient alternative to
    @flip 'apply'@.

    >>> map (<| 3) [(+ 1), (* 2)]
    [4,6]

    This is like the '$' operator from the "Prelude".
-}
infixr 0 <|
(<|) :: (a -> b) -> a -> b
f <| x = apply x f

-- ** Strict function application

{- |
    Strict function application.

    This is the strict version of 'apply'. It evaluates its argument with
    'seq' before applying it to the given function. In other words,
    @'apply'' x f@ is the same as @x \`seq\` 'apply' x f@.

    >>> apply' undefined (const 0)
    *** Exception: Prelude.undefined

    This is like the '$!' operator from the "Prelude".
-}
apply' :: a -> (a -> b) -> b
apply' x f = x `seq` apply x f

{- |
    Left-associative 'apply'' operator.

    This is the strict version of the '|>' operator.

    >>> undefined !> const 0
    *** Exception: Prelude.undefined

    This is like a flipped version of the '$!' operator from the "Prelude".
-}
infixl 0 !>
(!>) :: a -> (a -> b) -> b
x !> f = apply' x f

{- |
    Right-associative 'apply'' operator.

    This is the strict version of the '<!' operator.

    >>> const 0 <! undefined
    *** Exception: Prelude.undefined

    This is like the '$!' operator from the "Prelude".
-}
infixr 0 <!
(<!) :: (a -> b) -> a -> b
f <! x = apply' x f