{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveFunctor #-}
module Data.Profunctor.Mapping
( Mapping(..)
, CofreeMapping(..)
, FreeMapping(..)
, wanderMapping
, traverseMapping
, closedMapping
) where
import Control.Arrow (Kleisli(..))
import Data.Bifunctor.Tannen
import Data.Distributive
import Data.Functor.Compose
import Data.Functor.Identity
import Data.Profunctor.Choice
import Data.Profunctor.Closed
import Data.Profunctor.Monad
import Data.Profunctor.Strong
import Data.Profunctor.Traversing
import Data.Profunctor.Types
import Data.Profunctor.Unsafe
#if __GLASGOW_HASKELL__ < 710
import Control.Applicative
#endif
class (Traversing p, Closed p) => Mapping p where
map' :: Functor f => p a b -> p (f a) (f b)
map' = roam fmap
roam :: ((a -> b) -> s -> t)
-> p a b -> p s t
roam f = dimap (\s -> Bar $ \ab -> f ab s) lent . map'
newtype Bar t b a = Bar
{ runBar :: (a -> b) -> t }
deriving Functor
lent :: Bar t a a -> t
lent m = runBar m id
instance Mapping (->) where
map' = fmap
roam f = f
instance (Monad m, Distributive m) => Mapping (Kleisli m) where
map' (Kleisli f) = Kleisli (collect f)
#if __GLASGOW_HASKELL__ >= 710
roam f = Kleisli #. genMap f .# runKleisli
#else
roam f = (Kleisli . (unwrapMonad .)) #. genMapW f .# ((WrapMonad .) . runKleisli)
where
genMapW
:: (Monad m, Distributive m)
=> ((a -> b) -> s -> t)
-> (a -> WrappedMonad m b) -> s -> WrappedMonad m t
genMapW abst amb s = WrapMonad $ (\ab -> abst ab s) <$> distribute (unwrapMonad #. amb)
#endif
genMap :: Distributive f => ((a -> b) -> s -> t) -> (a -> f b) -> s -> f t
genMap abst afb s = fmap (\ab -> abst ab s) (distribute afb)
instance (Applicative m, Distributive m) => Mapping (Star m) where
map' (Star f) = Star (collect f)
roam f = Star #. genMap f .# runStar
instance (Functor f, Mapping p) => Mapping (Tannen f p) where
map' = Tannen . fmap map' . runTannen
wanderMapping :: Mapping p => (forall f. Applicative f => (a -> f b) -> s -> f t) -> p a b -> p s t
wanderMapping f = roam ((runIdentity .) #. f .# (Identity .))
traverseMapping :: (Mapping p, Functor f) => p a b -> p (f a) (f b)
traverseMapping = map'
closedMapping :: Mapping p => p a b -> p (x -> a) (x -> b)
closedMapping = map'
newtype CofreeMapping p a b = CofreeMapping { runCofreeMapping :: forall f. Functor f => p (f a) (f b) }
instance Profunctor p => Profunctor (CofreeMapping p) where
lmap f (CofreeMapping p) = CofreeMapping (lmap (fmap f) p)
rmap g (CofreeMapping p) = CofreeMapping (rmap (fmap g) p)
dimap f g (CofreeMapping p) = CofreeMapping (dimap (fmap f) (fmap g) p)
instance Profunctor p => Strong (CofreeMapping p) where
second' = map'
instance Profunctor p => Choice (CofreeMapping p) where
right' = map'
instance Profunctor p => Closed (CofreeMapping p) where
closed = map'
instance Profunctor p => Traversing (CofreeMapping p) where
traverse' = map'
wander f = roam $ (runIdentity .) #. f .# (Identity .)
instance Profunctor p => Mapping (CofreeMapping p) where
map' (CofreeMapping p) = CofreeMapping (dimap Compose getCompose p)
roam f (CofreeMapping p) =
CofreeMapping $
dimap (Compose #. fmap (\s -> Bar $ \ab -> f ab s)) (fmap lent .# getCompose) p
instance ProfunctorFunctor CofreeMapping where
promap f (CofreeMapping p) = CofreeMapping (f p)
instance ProfunctorComonad CofreeMapping where
proextract (CofreeMapping p) = runIdentity #. p .# Identity
produplicate (CofreeMapping p) = CofreeMapping (CofreeMapping (dimap Compose getCompose p))
data FreeMapping p a b where
FreeMapping :: Functor f => (f y -> b) -> p x y -> (a -> f x) -> FreeMapping p a b
instance Profunctor (FreeMapping p) where
lmap f (FreeMapping l m r) = FreeMapping l m (r . f)
rmap g (FreeMapping l m r) = FreeMapping (g . l) m r
dimap f g (FreeMapping l m r) = FreeMapping (g . l) m (r . f)
g #. FreeMapping l m r = FreeMapping (g #. l) m r
FreeMapping l m r .# f = FreeMapping l m (r .# f)
instance Strong (FreeMapping p) where
second' = map'
instance Choice (FreeMapping p) where
right' = map'
instance Closed (FreeMapping p) where
closed = map'
instance Traversing (FreeMapping p) where
traverse' = map'
wander f = roam ((runIdentity .) #. f .# (Identity .))
instance Mapping (FreeMapping p) where
map' (FreeMapping l m r) = FreeMapping (fmap l .# getCompose) m (Compose #. fmap r)
instance ProfunctorFunctor FreeMapping where
promap f (FreeMapping l m r) = FreeMapping l (f m) r
instance ProfunctorMonad FreeMapping where
proreturn p = FreeMapping runIdentity p Identity
projoin (FreeMapping l (FreeMapping l' m r') r) = FreeMapping ((l . fmap l') .# getCompose) m (Compose #. (fmap r' . r))