{-# LANGUAGE CPP #-}

module Control.Composition
    ( -- * Postcomposition
      (.*)
    , (.**)
    , (.***)
    -- * Precomposition
    , (-.)
    , (-.*)
    , (-.**)
    , (-.***)
    -- * Fancy function application
    , (-$)
    -- * Tuple helpers
    , both
    -- * Reexports from Control.Arrow
    , (&&&)
    , (***)
    -- * Reexports from Control.Monad
    , join
    , (=<<)
    , (>=>)
    , (<=<)
    -- * Reexports from base
    , (&)
    , fix
    , on
    , ap
    ) where

import           Control.Arrow ((&&&), (***))
#if __GLASGOW_HASKELL__ <= 783
import           Control.Monad (ap, join, (<=<), (>=>))
#else
import           Control.Monad (ap, join, (<=<), (=<<), (>=>))
#endif
#if __GLASGOW_HASKELL__ > 784
import           Data.Function (fix, on, (&))
#else
import           Data.Function (fix, on)
#endif

infixr 8 .*
infixr 8 .**
infixr 8 .***
infixr 8 -.*
infixr 8 -.**
infixr 8 -.***
infixl 8 -$
#if __GLASGOW_HASKELL__ <= 784
infixl 1 &

(&) :: a -> (a -> b) -> b
(&) x f = f x
#endif

both :: (a -> b) -> (a, a) -> (b, b)
both = join (***)

(-$) :: (a -> b -> c) -> b -> a -> c
(-$) f x y = f y x

-- | As an example:
--
-- > λ:> ((*2) .* (+)) 1 3 4
-- > 16
(.*) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
(.*) f g x y = f (g x y)

(.**) :: (d -> e) -> (a -> b -> c -> d) -> a -> b -> c -> e
(.**) f g x y z = f (g x y z)

(.***) :: (e -> f) -> (a -> b -> c -> d -> e) -> a -> b -> c -> d -> f
(.***) f g w x y z = f (g w x y z)

-- | The Oedipus combinator
(-.*) :: (b -> c) -> (a -> c -> d) -> a -> b -> d
(-.*) f g x y = g x (f y)

(-.**) :: (c -> d) -> (a -> b -> d -> e) -> a -> b -> c -> e
(-.**) f g x y z = g x y (f z)

(-.***) :: (d -> e) -> (a -> b -> c -> e -> f) -> a -> b -> c -> d -> f
(-.***) f g w x y z = g w x y (f z)

-- | Backwards function composition
(-.) :: (a -> b) -> (b -> c) -> a -> c
(-.) f g x = g (f x)