------------------------------------------------------------------------------------------- -- | -- Module : Control.Functor.Yoneda -- Copyright : 2008 Edward Kmett -- License : BSD -- -- Maintainer : Edward Kmett -- Stability : experimental -- Portability : portable -- -- The Yoneda lemma can be realized as the Kan extension along Identity -- However, having this special instance allows us to define Yoneda f as a monad, -- comonad, etc. based on whatever properties the base functor has, without -- limiting ourselves to what Ran f f can manage. -- -- Performance wise, Yoneda may make your monad more efficient at handling a bunch of -- fmaps, while CoYoneda may do the same for a comonad assuming you require a greater than -- linear amount of time to fmap over your structure. You can apply each in either role -- but the asymptotics will probably not be in your favor. -- ------------------------------------------------------------------------------------------- module Control.Functor.Yoneda ( Yoneda(Yoneda,runYoneda), ranToYoneda, yonedaToRan, lowerYoneda , CoYoneda(CoYoneda), lanToCoYoneda, coYonedaToLan, liftCoYoneda ) where import Control.Applicative import Control.Comonad.HigherOrder import Control.Comonad.Cofree import Control.Comonad.Context import Control.Comonad.Reader import Control.Comonad.Trans import Control.Functor.Extras import Control.Functor.KanExtension import Control.Functor.Pointed import Control.Functor.HigherOrder import Control.Monad.Identity import Control.Monad.HigherOrder import Control.Monad.Free import Control.Monad.Trans import Control.Monad.Reader.Class import Control.Monad.State.Class import Control.Monad.Writer.Class -- Yoneda ~ Ran Identity newtype Yoneda f a = Yoneda { runYoneda :: forall b. ((a -> b) -> f b) } ranToYoneda :: Ran Identity f :~> Yoneda f ranToYoneda r = Yoneda (\f -> runRan r (Identity . f)) yonedaToRan :: Yoneda f :~> Ran Identity f yonedaToRan y = Ran (\f -> runYoneda y (runIdentity . f)) lowerYoneda :: Yoneda f :~> f lowerYoneda m = runYoneda m id instance Functor (Yoneda f) where fmap f m = Yoneda (\k -> runYoneda m (k . f)) instance Pointed f => Pointed (Yoneda f) where point a = Yoneda (\f -> point (f a)) instance Applicative f => Applicative (Yoneda f) where pure a = Yoneda (\f -> pure (f a)) m <*> n = Yoneda (\f -> runYoneda m (f .) <*> runYoneda n id) instance Monad f => Monad (Yoneda f) where return a = Yoneda (\f -> return (f a)) m >>= k = Yoneda (\f -> runYoneda m id >>= \a -> runYoneda (k a) f) instance HFunctor Yoneda where ffmap = fmap hfmap f y = Yoneda (f . runYoneda y) -- f a -> Yoneda f a instance HPointed Yoneda where hreturn a = Yoneda (\f -> fmap f a) -- exists because Monad doesn't require Functor! instance MonadTrans Yoneda where lift a = Yoneda (\f -> liftM f a) instance ComonadTrans Yoneda where colift = hreturn -- Yoneda f a -> f a instance HCopointed Yoneda where hextract t = runYoneda t id instance HMonad Yoneda where hbind f = f . hextract instance HComonad Yoneda where hextend f = hreturn . f instance Copointed f => Copointed (Yoneda f) where extract = extract . hextract instance Comonad f => Comonad (Yoneda f) where extend k m = Yoneda (\f -> extend (f . k . hreturn) (hextract m)) instance MonadState e m => MonadState e (Yoneda m) where get = lift get put = lift . put instance MonadReader e m => MonadReader e (Yoneda m) where ask = lift ask local r = lift . local r . lowerYoneda instance MonadWriter e m => MonadWriter e (Yoneda m) where tell = lift . tell listen = lift . listen . flip runYoneda id pass = lift . pass . lowerYoneda instance MonadFree f m => MonadFree f (Yoneda m) where inFree = lift . inFree . fmap lowerYoneda instance RunMonadFree f m => RunMonadFree f (Yoneda m) where cataFree l r = cataFree l r . lowerYoneda instance ComonadCofree f m => ComonadCofree f (Yoneda m) where outCofree = fmap colift . outCofree . lowerYoneda instance RunComonadCofree f m => RunComonadCofree f (Yoneda m) where anaCofree l r = colift . anaCofree l r instance ComonadContext e m => ComonadContext e (Yoneda m) where getC = getC . lowerYoneda modifyC s = modifyC s . lowerYoneda instance ComonadReader e m => ComonadReader e (Yoneda m) where askC = askC . lowerYoneda -- | Left Kan Extensions -- CoYoneda ~ Lan Identity data CoYoneda f a = forall b. CoYoneda (b -> a) (f b) lanToCoYoneda :: Lan Identity f :~> CoYoneda f lanToCoYoneda (Lan f v) = CoYoneda (f . Identity) v coYonedaToLan :: CoYoneda f :~> Lan Identity f coYonedaToLan (CoYoneda f v) = Lan (f . runIdentity) v instance Functor (CoYoneda f) where fmap f (CoYoneda g v) = CoYoneda (f . g) v instance Pointed f => Pointed (CoYoneda f) where point = hreturn . point instance Applicative f => Applicative (CoYoneda f) where pure = hreturn . pure m <*> n = CoYoneda id (hextract m <*> hextract n) instance Monad m => Monad (CoYoneda m) where return = CoYoneda id . return CoYoneda f v >>= k = CoYoneda id (v >>= (\(CoYoneda f' v') -> liftM f' v') . k . f) instance HFunctor CoYoneda where ffmap = fmap hfmap f (CoYoneda g v) = CoYoneda g (f v) instance HPointed CoYoneda where hreturn = CoYoneda id instance HMonad CoYoneda where hbind f = f . hextract instance HComonad CoYoneda where hextend f = hreturn . f instance HCopointed CoYoneda where hextract (CoYoneda f v) = fmap f v liftCoYoneda :: f :~> CoYoneda f liftCoYoneda = CoYoneda id -- | Just a conceptual nicety for monads since they aren't functors in Haskell. this is otherwise just hextract lowerCoYoneda :: Monad f => CoYoneda f :~> f lowerCoYoneda (CoYoneda f v) = liftM f v instance Copointed w => Copointed (CoYoneda w) where extract (CoYoneda f v) = f (extract v) instance Comonad w => Comonad (CoYoneda w) where extend k (CoYoneda f v) = CoYoneda id $ extend (k . CoYoneda f) v instance MonadTrans CoYoneda where lift = CoYoneda id instance ComonadTrans CoYoneda where colift = CoYoneda id -- All the (Co)monadFoo CoYoneda instances instance ComonadCofree f m => ComonadCofree f (CoYoneda m) where outCofree = fmap colift . outCofree . hextract instance RunComonadCofree f m => RunComonadCofree f (CoYoneda m) where anaCofree l r = colift . anaCofree l r instance ComonadContext e m => ComonadContext e (CoYoneda m) where getC = getC . hextract modifyC s = modifyC s . hextract instance ComonadReader e m => ComonadReader e (CoYoneda m) where askC = askC . hextract instance MonadState e m => MonadState e (CoYoneda m) where get = lift get put = lift . put instance MonadReader e m => MonadReader e (CoYoneda m) where ask = lift ask local r = lift . local r . lowerCoYoneda instance MonadWriter e m => MonadWriter e (CoYoneda m) where tell = lift . tell listen = lift . listen . lowerCoYoneda pass = lift . pass . lowerCoYoneda instance MonadFree f m => MonadFree f (CoYoneda m) where inFree = lift . inFree . fmap lowerCoYoneda instance RunMonadFree f m => RunMonadFree f (CoYoneda m) where cataFree l r = cataFree l r . lowerCoYoneda