{-# 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 -- Stability : provisional -- Portability : GADTs, MPTCs, fundeps -- -- 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 #-}