packages feed

camfort-0.905: src/Language/Fortran/Model/Util.hs

{-|

Miscellaneous combinators.

-}
module Language.Fortran.Model.Util where

import           Control.Applicative
import           Control.Monad.Reader

import           Data.Function       ((&), on)

--------------------------------------------------------------------------------
--  Combinators
--------------------------------------------------------------------------------

-- | Like 'on', but apply a different function to each argument (which are
-- allowed to have different types).
on2 :: (c -> d -> e) -> (a -> c) -> (b -> d) -> a -> b -> e
on2 h g f = (h . g) *.. f


-- | '..*' in the Kleisli category.
matchingWithBoth :: (Monad m) => (a -> b -> m c) -> (c -> m r) -> a -> b -> m r
matchingWithBoth f k = (>>= k) ..* f


-- | 'on2' in the Kleisli category.
matchingWith2 :: (Monad m) => (a -> m a') -> (b -> m b') -> ((a', b') -> m r) -> a -> b -> m r
matchingWith2 = matchingWithBoth ..* on2 (liftA2 (,))


-- | Alternative @('<|>')@ over single-argument functions.
altf :: (Alternative f) => (a -> f b) -> (a -> f b) -> a -> f b
altf = runReaderT ..* (<|>) `on` ReaderT


-- | Alternative @('<|>')@ over two-argument functions.
altf2 :: (Alternative f) => (a -> b -> f c) -> (a -> b -> f c) -> a -> b -> f c
altf2 = curry ..* altf `on` uncurry

-- | Flipped 'fmap'.
(<$$>) :: (Functor f) => f a -> (a -> b) -> f b
(<$$>) = flip (<$>)

-- | Flipped function application.
with :: a -> (a -> b) -> b
with = (&)

-- | @(f *.. g) x y = f x (g y)@. Mnemonic: the @*@ is next to the function
-- which has two arguments.
(*..) :: (a -> c -> d) -> (b -> c) -> a -> b -> d
(f *.. g) x y = f x (g y)

-- | @(f ..* g) x y = f (g x y)@. Mnemonic: the @*@ is next to the function
-- which has two arguments.
(..*) :: (c -> d) -> (a -> b -> c) -> a -> b -> d
f ..* g = curry (f . uncurry g)