content: {-# OPTIONS_HADDOCK show-extensions #-}
  
  {-# LANGUAGE Arrows #-}
  {-# LANGUAGE RankNTypes #-}
  
  {-|
  Module      : Data.Utils.Arrow
  Description : arrow utilities
  Copyright   : (c) Lars Brünjes, 2016
  License     : MIT
  Maintainer  : brunjlar@gmail.com
  Stability   : experimental
  Portability : portable
  
  This module defines utility functions for /arrows/.
  -}
  
  module Data.Utils.Arrow
      ( ArrowConvolve(..)
      , fmapArr
      , pureArr
      , apArr
      , dimapArr
      ) where
  
  import Control.Arrow
  
  -- | Arrows implementing 'ArrowConvolve' can be mapped over containers.
  --   This means that every functor (@f :: Hask -> Hask@) lifts to a functor (@a -> a@).
  --
  --   Instances should satisfy the following laws:
  --
  --   * @convolve id = id@
  --
  --   * @convolve (g . h) = convolve g . convolve h@
  --
  --   * @convolve . arr = arr . fmap@
  --
  class Arrow a => ArrowConvolve a where
  
      convolve :: forall f b c. Functor f => a b c -> a (f b) (f c)
  
  -- | A function suitable to define the canonical 'Functor' instance for arrows.
  --
  fmapArr :: Arrow a => (c -> d) -> a b c -> a b d
  fmapArr f a = a >>^ f
  
  -- | A function to define 'pure' for arrows.
  -- Combining this with 'apArr', the canonical 'Applicative' instance for arrows can easily be defined.
  --
  pureArr :: Arrow a => c -> a b c
  pureArr = arr . const
  
  -- | A function to define @('<*>')@ for arrows.
  -- Combining this with 'pureArr', the canonical 'Applicative' instance for arrows can easily be defined.
  --
  apArr :: Arrow a => a b (c -> d) -> a b c -> a b d
  apArr a b = proc x -> do
      f <- a -< x
      y <- b -< x
      returnA -< f y
  
  -- | A function suitable to define the canonical 'Data.Profunctor.Profunctor' instance for arrows.
  --
  dimapArr :: Arrow a => (b -> c) -> (d -> e) -> a c d -> a b e
  dimapArr f g a = f ^>> a >>^ g
  