kan-extensions-3.5: src/Data/Functor/Yoneda/Reduction.hs
{-# LANGUAGE CPP, GADTs, FlexibleContexts, MultiParamTypeClasses, UndecidableInstances, TypeFamilies #-}
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE Trustworthy #-}
#endif
-----------------------------------------------------------------------------
-- |
-- Copyright : (C) 2011-2013 Edward Kmett
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : Edward Kmett <ekmett@gmail.com>
-- Stability : provisional
-- Portability : GADTs, MPTCs, fundeps
--
-- Yoneda Reduction:
--
-- <http://ncatlab.org/nlab/show/Yoneda+reduction>
--
-- @Yoneda f@ is isomorphic to @Lan f Identity@
----------------------------------------------------------------------------
module Data.Functor.Yoneda.Reduction
( Yoneda(..)
, liftYoneda
, lowerYoneda
, lowerM
) where
import Control.Applicative
import Control.Monad (MonadPlus(..), liftM)
import Control.Monad.Fix
import Control.Monad.Trans.Class
import Control.Comonad
import Control.Comonad.Trans.Class
import Data.Distributive
import Data.Function (on)
import Data.Functor.Bind
import Data.Functor.Extend
import Data.Functor.Plus
import Data.Functor.Adjunction
import Data.Functor.Representable
import Data.Key
import Data.Foldable
import Data.Traversable
import Data.Semigroup.Foldable
import Data.Semigroup.Traversable
import Prelude hiding (sequence, lookup, zipWith)
import Text.Read hiding (lift)
-- | A form suitable for Yoneda reduction
data Yoneda f a where
Yoneda :: (b -> a) -> f b -> Yoneda f a
-- | Yoneda "expansion"
liftYoneda :: f a -> Yoneda f a
liftYoneda = Yoneda id
{-# INLINE liftYoneda #-}
-- | Yoneda reduction
lowerYoneda :: Functor f => Yoneda f a -> f a
lowerYoneda (Yoneda f m) = fmap f m
{-# INLINE lowerYoneda #-}
-- | Yoneda reduction given a 'Monad'.
lowerM :: Monad f => Yoneda f a -> f a
lowerM (Yoneda f m) = liftM f m
{-# INLINE lowerM #-}
instance Functor (Yoneda f) where
fmap f (Yoneda g v) = Yoneda (f . g) v
{-# INLINE fmap #-}
type instance Key (Yoneda f) = Key f
instance Keyed f => Keyed (Yoneda f) where
mapWithKey f (Yoneda k a) = Yoneda id $ mapWithKey (\x -> f x . k) a
{-# INLINE mapWithKey #-}
instance Apply f => Apply (Yoneda f) where
m <.> n = liftYoneda $ lowerYoneda m <.> lowerYoneda n
{-# INLINE (<.>) #-}
instance Applicative f => Applicative (Yoneda f) where
pure = liftYoneda . pure
{-# INLINE pure #-}
m <*> n = liftYoneda $ lowerYoneda m <*> lowerYoneda n
{-# INLINE (<*>) #-}
instance Zip f => Zip (Yoneda f) where
zipWith f m n = liftYoneda $ zipWith f (lowerYoneda m) (lowerYoneda n)
{-# INLINE zipWith #-}
instance ZipWithKey f => ZipWithKey (Yoneda f) where
zipWithKey f m n = liftYoneda $ zipWithKey f (lowerYoneda m) (lowerYoneda n)
{-# INLINE zipWithKey #-}
instance Alternative f => Alternative (Yoneda f) where
empty = liftYoneda empty
{-# INLINE empty #-}
m <|> n = liftYoneda $ lowerYoneda m <|> lowerYoneda n
{-# INLINE (<|>) #-}
instance Alt f => Alt (Yoneda f) where
m <!> n = liftYoneda $ lowerYoneda m <!> lowerYoneda n
{-# INLINE (<!>) #-}
instance Plus f => Plus (Yoneda f) where
zero = liftYoneda zero
{-# INLINE zero #-}
instance Bind m => Bind (Yoneda m) where
Yoneda f v >>- k = liftYoneda (v >>- lowerYoneda . k . f)
{-# INLINE (>>-) #-}
instance Monad m => Monad (Yoneda m) where
return = Yoneda id . return
{-# INLINE return #-}
Yoneda f v >>= k = lift (v >>= lowerM . k . f)
{-# INLINE (>>=) #-}
instance MonadTrans Yoneda where
lift = Yoneda id
{-# INLINE lift #-}
instance MonadFix f => MonadFix (Yoneda f) where
mfix f = lift $ mfix (lowerM . f)
{-# INLINE mfix #-}
instance MonadPlus f => MonadPlus (Yoneda f) where
mzero = lift mzero
{-# INLINE mzero #-}
m `mplus` n = lift $ lowerM m `mplus` lowerM n
{-# INLINE mplus #-}
instance (Functor f, Lookup f) => Lookup (Yoneda f) where
lookup k f = lookup k (lowerYoneda f)
{-# INLINE lookup #-}
instance (Functor f, Indexable f) => Indexable (Yoneda f) where
index = index . lowerYoneda
{-# INLINE index #-}
instance Representable f => Representable (Yoneda f) where
tabulate = liftYoneda . tabulate
{-# INLINE tabulate #-}
instance Extend w => Extend (Yoneda w) where
extended k (Yoneda f v) = Yoneda id $ extended (k . Yoneda f) v
{-# INLINE extended #-}
instance Comonad w => Comonad (Yoneda w) where
extend k (Yoneda f v) = Yoneda id $ extend (k . Yoneda f) v
{-# INLINE extend #-}
extract (Yoneda f v) = f (extract v)
{-# INLINE extract #-}
instance ComonadTrans Yoneda where
lower (Yoneda f a) = fmap f a
{-# INLINE lower #-}
instance Foldable f => Foldable (Yoneda f) where
foldMap f (Yoneda k a) = foldMap (f . k) a
{-# INLINE foldMap #-}
instance FoldableWithKey f => FoldableWithKey (Yoneda f) where
foldMapWithKey f (Yoneda k a) = foldMapWithKey (\x -> f x . k) a
{-# INLINE foldMapWithKey #-}
instance Foldable1 f => Foldable1 (Yoneda f) where
foldMap1 f (Yoneda k a) = foldMap1 (f . k) a
{-# INLINE foldMap1 #-}
instance FoldableWithKey1 f => FoldableWithKey1 (Yoneda f) where
foldMapWithKey1 f (Yoneda k a) = foldMapWithKey1 (\x -> f x . k) a
{-# INLINE foldMapWithKey1 #-}
instance Traversable f => Traversable (Yoneda f) where
traverse f (Yoneda k a) = Yoneda id <$> traverse (f . k) a
{-# INLINE traverse #-}
instance Traversable1 f => Traversable1 (Yoneda f) where
traverse1 f (Yoneda k a) = Yoneda id <$> traverse1 (f . k) a
{-# INLINE traverse1 #-}
instance TraversableWithKey f => TraversableWithKey (Yoneda f) where
traverseWithKey f (Yoneda k a) = Yoneda id <$> traverseWithKey (\x -> f x . k) a
{-# INLINE traverseWithKey #-}
instance TraversableWithKey1 f => TraversableWithKey1 (Yoneda f) where
traverseWithKey1 f (Yoneda k a) = Yoneda id <$> traverseWithKey1 (\x -> f x . k) a
{-# INLINE traverseWithKey1 #-}
instance Distributive f => Distributive (Yoneda f) where
collect f = liftYoneda . collect (lowerYoneda . f)
{-# INLINE collect #-}
instance (Functor f, Show (f a)) => Show (Yoneda f a) where
showsPrec d (Yoneda f a) = showParen (d > 10) $
showString "liftYoneda " . showsPrec 11 (fmap f a)
{-# INLINE showsPrec #-}
#ifdef __GLASGOW_HASKELL__
instance (Functor f, Read (f a)) => Read (Yoneda f a) where
readPrec = parens $ prec 10 $ do
Ident "liftYoneda" <- lexP
liftYoneda <$> step readPrec
{-# INLINE readPrec #-}
#endif
instance (Functor f, Eq (f a)) => Eq (Yoneda f a) where
(==) = (==) `on` lowerYoneda
{-# INLINE (==) #-}
instance (Functor f, Ord (f a)) => Ord (Yoneda f a) where
compare = compare `on` lowerYoneda
{-# INLINE compare #-}
instance Adjunction f g => Adjunction (Yoneda f) (Yoneda g) where
unit = liftYoneda . fmap liftYoneda . unit
{-# INLINE unit #-}
counit = counit . fmap lowerYoneda . lowerYoneda
{-# INLINE counit #-}