content: 
  {-|
  
  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)
  