comonad 0.3.0 → 0.4.0
raw patch · 2 files changed
+214/−98 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Comonad: class Comonad w => ComonadZip w
- Control.Comonad: instance ComonadZip Identity
- Control.Comonad: instance ComonadZip d => ArrowLoop (Cokleisli d)
- Control.Comonad: instance ComonadZip w => ComonadZip (IdentityT w)
- Control.Comonad: instance Monoid m => ComonadZip ((,) m)
- Control.Comonad: instance Monoid m => ComonadZip ((->) m)
- Control.Comonad: unfoldW :: Comonad w => (w b -> (a, b)) -> w b -> [a]
+ Control.Comonad: ($>) :: Functor f => f a -> b -> f b
+ Control.Comonad: (<$>) :: Functor f => (a -> b) -> f a -> f b
+ Control.Comonad: WrapApply :: Either (f a) a -> WrappedApply f a
+ Control.Comonad: WrappedApplicative :: f a -> WrappedApplicative f a
+ Control.Comonad: class (Comonad w, FunctorApply w) => ComonadApply w
+ Control.Comonad: class Functor f => FunctorApply f
+ Control.Comonad: instance Applicative (Cokleisli w a)
+ Control.Comonad: instance Applicative f => Applicative (WrappedApplicative f)
+ Control.Comonad: instance Applicative f => FunctorApply (WrappedApplicative f)
+ Control.Comonad: instance Arrow a => FunctorApply (WrappedArrow a b)
+ Control.Comonad: instance Comonad f => Comonad (WrappedApply f)
+ Control.Comonad: instance ComonadApply Identity
+ Control.Comonad: instance ComonadApply f => ComonadApply (WrappedApply f)
+ Control.Comonad: instance ComonadApply w => ArrowLoop (Cokleisli w)
+ Control.Comonad: instance ComonadApply w => ComonadApply (IdentityT w)
+ Control.Comonad: instance Functor f => Functor (WrappedApplicative f)
+ Control.Comonad: instance Functor f => Functor (WrappedApply f)
+ Control.Comonad: instance FunctorApply (Cokleisli w a)
+ Control.Comonad: instance FunctorApply IO
+ Control.Comonad: instance FunctorApply Identity
+ Control.Comonad: instance FunctorApply Maybe
+ Control.Comonad: instance FunctorApply ZipList
+ Control.Comonad: instance FunctorApply []
+ Control.Comonad: instance FunctorApply f => Applicative (WrappedApply f)
+ Control.Comonad: instance FunctorApply f => FunctorApply (WrappedApply f)
+ Control.Comonad: instance FunctorApply w => FunctorApply (IdentityT w)
+ Control.Comonad: instance Monad m => FunctorApply (WrappedMonad m)
+ Control.Comonad: instance Monoid m => ComonadApply ((,) m)
+ Control.Comonad: instance Monoid m => ComonadApply ((->) m)
+ Control.Comonad: instance Monoid m => FunctorApply ((,) m)
+ Control.Comonad: instance Monoid m => FunctorApply ((->) m)
+ Control.Comonad: instance Monoid m => FunctorApply (Const m)
+ Control.Comonad: liftF2 :: FunctorApply w => (a -> b -> c) -> w a -> w b -> w c
+ Control.Comonad: liftF3 :: FunctorApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
+ Control.Comonad: newtype WrappedApplicative f a
+ Control.Comonad: newtype WrappedApply f a
+ Control.Comonad: unwrapApplicative :: WrappedApplicative f a -> f a
+ Control.Comonad: unwrapApply :: WrappedApply f a -> Either (f a) a
- Control.Comonad: (.>) :: ComonadZip w => w a -> w b -> w b
+ Control.Comonad: (.>) :: FunctorApply f => f a -> f b -> f b
- Control.Comonad: (<.) :: ComonadZip w => w a -> w b -> w a
+ Control.Comonad: (<.) :: FunctorApply f => f a -> f b -> f a
- Control.Comonad: (<..>) :: ComonadZip w => w a -> w (a -> b) -> w b
+ Control.Comonad: (<..>) :: FunctorApply w => w a -> w (a -> b) -> w b
- Control.Comonad: (<.>) :: ComonadZip w => w (a -> b) -> w a -> w b
+ Control.Comonad: (<.>) :: FunctorApply f => f (a -> b) -> f a -> f b
- Control.Comonad: liftW2 :: ComonadZip w => (a -> b -> c) -> w a -> w b -> w c
+ Control.Comonad: liftW2 :: ComonadApply w => (a -> b -> c) -> w a -> w b -> w c
- Control.Comonad: liftW3 :: ComonadZip w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
+ Control.Comonad: liftW3 :: ComonadApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d
Files
- Control/Comonad.hs +213/−97
- comonad.cabal +1/−1
Control/Comonad.hs view
@@ -11,37 +11,36 @@ -- -- A 'Comonad' is the categorical dual of a 'Monad'. -----------------------------------------------------------------------------module Control.Comonad- ( - -- * Functor and Comonad+module Control.Comonad ( + -- * Functors Functor(..)- , Comonad(..)- -- * Functions-- -- ** Naming conventions- -- $naming-- -- ** Operators- , (=>=) -- :: Comonad w => (w a -> b) -> (w b -> c) -> w a -> c- , (=<=) -- :: Comonad w => (w b -> c) -> (w a -> b) -> w a -> c- , (=>>) -- :: Comonad w => w a -> (w a -> b) -> w b- , (<<=) -- :: Comonad w => (w a -> b) -> w a -> w b+ , (<$>) -- :: Functor f => (a -> b) -> f a -> f b+ , ( $>) -- :: Functor f => f a -> b -> f b - -- * Fixed points and folds- , wfix -- :: Comonad w => w (w a -> a) -> a- , unfoldW -- :: Comonad w => (w b -> (a,b)) -> w b -> [a]+ -- * Comonads+ , Comonad(..)+ , (=>=) -- :: Comonad w => (w a -> b) -> (w b -> c) -> w a -> c+ , (=<=) -- :: Comonad w => (w b -> c) -> (w a -> b) -> w a -> c+ , (=>>) -- :: Comonad w => w a -> (w a -> b) -> w b+ , (<<=) -- :: Comonad w => (w a -> b) -> w a -> w b+ , liftW -- :: Comonad w => (a -> b) -> w a -> w b+ , wfix -- :: Comonad w => w (w a -> a) -> a - -- ** Comonadic lifting - , liftW -- :: Comonad w => (a -> b) -> w a -> w b+ -- * FunctorApply - strong lax symmetric semimonoidal endofunctors+ , FunctorApply(..)+ , (<..>) -- :: FunctorApply w => w a -> w (a -> b) -> w b+ , liftF2 -- :: FunctorApply w => (a -> b -> c) -> w a -> w b -> w c+ , liftF3 -- :: FunctorApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d - -- * Comonads with Zipping- , ComonadZip(..)- , (<..>) -- :: ComonadZip w => w a -> w (a -> b) -> w b- , liftW2 -- :: ComonadZip w => (a -> b -> c) -> w a -> w b -> w c- , liftW3 -- :: ComonadZip w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d+ -- * ComonadApply - strong lax symmetric semimonoidal comonads+ , ComonadApply+ , liftW2 -- :: ComonadApply w => (a -> b -> c) -> w a -> w b -> w c+ , liftW3 -- :: ComonadApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d - -- * Cokleisli Arrows+ -- * Wrappers , Cokleisli(..)+ , WrappedApplicative(..)+ , WrappedApply(..) ) where import Prelude hiding (id, (.))@@ -55,9 +54,13 @@ infixl 1 =>> infixr 1 <<=, =<=, =>= -infixl 4 <.>, <., .>, <..>+infixl 4 <.>, <., .>, <..>, $> -{-|+($>) :: Functor f => f a -> b -> f b+($>) = flip (<$)++{- |+ There are two ways to define a comonad: I. Provide definitions for 'extract' and 'extend'@@ -96,22 +99,29 @@ > fmap f = extend (f . extract) These are the default definitions of 'extend' and'duplicate' and -the 'default' definition of 'liftW' respectively.+the definition of 'liftW' respectively.+ -} class Functor w => Comonad w where- -- | aka coreturn- extract:: w a -> a- -- | aka cojoin+ -- | + -- > extract . fmap f = f . extract+ extract :: w a -> a+ -- | + -- > duplicate = extend id+ -- > fmap (fmap f) . duplicate = duplicate . fmap f duplicate :: w a -> w (w a)- -- | aka cobind- extend :: (w a -> b) -> w a -> w b+ -- |+ -- > extend f = fmap f . duplicate+ extend :: (w a -> b) -> w a -> w b extend f = fmap f . duplicate duplicate = extend id -- | A suitable default definition for 'fmap' for a 'Comonad'. -- Promotes a function to a comonad.+--+-- > fmap f = extend (f . extract) liftW :: Comonad w => (a -> b) -> w a -> w b liftW f = extend (f . extract) {-# INLINE liftW #-}@@ -136,20 +146,18 @@ f =>= g = g . extend f {-# INLINE (=>=) #-} --- | A generalized comonadic list anamorphism-unfoldW :: Comonad w => (w b -> (a,b)) -> w b -> [a]-unfoldW f w = fst (f w) : unfoldW f (w =>> snd . f)- -- | Comonadic fixed point wfix :: Comonad w => w (w a -> a) -> a wfix w = extract w (extend wfix w) -- * Comonads for Prelude types:---- Instances: While Control.Comonad.Instances would be more symmetric with the definition of--- Control.Monad.Instances in base, the reason the latter exists is because of Haskell 98 specifying--- the types Either a, ((,)m) and ((->)e) and the class Monad without having the foresight to require --- or allow instances between them. Here Haskell 98 says nothing about Comonads, so we can include the +--+-- Instances: While Control.Comonad.Instances would be more symmetric+-- with the definition of Control.Monad.Instances in base, the reason+-- the latter exists is because of Haskell 98 specifying the types+-- @'Either' a@, @((,)m)@ and @((->)e)@ and the class Monad without+-- having the foresight to require or allow instances between them.+-- Here Haskell 98 says nothing about Comonads, so we can include the -- instances directly avoiding the wart of orphan instances. instance Comonad ((,)e) where@@ -161,7 +169,7 @@ duplicate f m = f . mappend m -- * Comonads for types from 'transformers'.-+-- -- This isn't really a transformer, so i have no compunction about including the instance here. -- TODO: Petition to move Data.Functor.Identity into base instance Comonad Identity where@@ -175,57 +183,183 @@ extract = extract . runIdentityT extend f (IdentityT m) = IdentityT (extend (f . IdentityT) m) -{- | +-- | A strong lax symmetric semi-monoidal functor. -As a symmetric semi-monoidal comonad, an instance of ComonadZip is required to satisfy:+class Functor f => FunctorApply f where+ (<.>) :: f (a -> b) -> f a -> f b -> extract (a <.> b) = extract a (extract b)+ -- | a .> b = const id <$> a <.> b+ (.>) :: f a -> f b -> f b+ a .> b = const id <$> a <.> b -Minimal definition: '<.>'+ -- | a <. b = const <$> a <.> b+ (<.) :: f a -> f b -> f a+ a <. b = const <$> a <.> b -Based on the ComonadZip from \"The Essence of Dataflow Programming\" -by Tarmo Uustalu and Varmo Vene, but adapted to fit the programming style of-Control.Applicative. +-- this only requires a Semigroup+instance Monoid m => FunctorApply ((,)m) where+ (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>) --}-class Comonad w => ComonadZip w where- (<.>) :: w (a -> b) -> w a -> w b- (.>) :: w a -> w b -> w b- (<.) :: w a -> w b -> w a+-- this only requires a Semigroup+instance Monoid m => FunctorApply ((->)m) where+ (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>) - a .> b = const id <$> a <.> b- a <. b = const <$> a <.> b- -instance Monoid m => ComonadZip ((,)m) where+instance FunctorApply ZipList where (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>) -instance Monoid m => ComonadZip ((->)m) where+instance FunctorApply [] where (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>) -instance ComonadZip Identity where+instance FunctorApply IO where (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>) -instance ComonadZip w => ComonadZip (IdentityT w) where+instance FunctorApply Maybe where+ (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>)++instance FunctorApply Identity where+ (<.>) = (<*>)+ (<. ) = (<* )+ ( .>) = ( *>)++instance FunctorApply w => FunctorApply (IdentityT w) where IdentityT wa <.> IdentityT wb = IdentityT (wa <.> wb) +instance Monad m => FunctorApply (WrappedMonad m) where+ (<.>) = (<*>) + (<. ) = (<* )+ ( .>) = ( *>)++instance Monoid m => FunctorApply (Const m) where+ (<.>) = (<*>) + (<. ) = (<* )+ ( .>) = ( *>)++instance Arrow a => FunctorApply (WrappedArrow a b) where+ (<.>) = (<*>) + (<. ) = (<* )+ ( .>) = ( *>)++-- | Wrap Applicatives to be used as a member of FunctorApply +newtype WrappedApplicative f a = WrappedApplicative { unwrapApplicative :: f a } ++instance Functor f => Functor (WrappedApplicative f) where+ fmap f (WrappedApplicative a) = WrappedApplicative (f <$> a)++instance Applicative f => FunctorApply (WrappedApplicative f) where+ WrappedApplicative f <.> WrappedApplicative a = WrappedApplicative (f <*> a)+ WrappedApplicative a <. WrappedApplicative b = WrappedApplicative (a <* b)+ WrappedApplicative a .> WrappedApplicative b = WrappedApplicative (a *> b)++instance Applicative f => Applicative (WrappedApplicative f) where+ pure = WrappedApplicative . pure+ WrappedApplicative f <*> WrappedApplicative a = WrappedApplicative (f <*> a)+ WrappedApplicative a <* WrappedApplicative b = WrappedApplicative (a <* b)+ WrappedApplicative a *> WrappedApplicative b = WrappedApplicative (a *> b)+ +-- | Transform a strong lax symmetric semi-monoidal endofunctor into a strong lax symmetric+-- monoidal endofunctor by adding a unit.+newtype WrappedApply f a = WrapApply { unwrapApply :: Either (f a) a }++instance Functor f => Functor (WrappedApply f) where+ fmap f (WrapApply (Right a)) = WrapApply (Right (f a ))+ fmap f (WrapApply (Left fa)) = WrapApply (Left (f <$> fa))++instance FunctorApply f => FunctorApply (WrappedApply f) where+ WrapApply (Right f) <.> WrapApply (Right a) = WrapApply (Right (f a ))+ WrapApply (Right f) <.> WrapApply (Left fa) = WrapApply (Left (f <$> fa))+ WrapApply (Left ff) <.> WrapApply (Right a) = WrapApply (Left (($a) <$> ff))+ WrapApply (Left ff) <.> WrapApply (Left fa) = WrapApply (Left (ff <.> fa))++ WrapApply a <. WrapApply (Right _) = WrapApply a+ WrapApply (Right a) <. WrapApply (Left fb) = WrapApply (Left (a <$ fb))+ WrapApply (Left fa) <. WrapApply (Left fb) = WrapApply (Left (fa <. fb))++ WrapApply (Right _) .> WrapApply b = WrapApply b+ WrapApply (Left fa) .> WrapApply (Right b) = WrapApply (Left (fa $> b ))+ WrapApply (Left fa) .> WrapApply (Left fb) = WrapApply (Left (fa .> fb))+ +instance FunctorApply f => Applicative (WrappedApply f) where+ pure a = WrapApply (Right a)+ (<*>) = (<.>)+ (<* ) = (<. )+ ( *>) = ( .>)++instance Comonad f => Comonad (WrappedApply f) where+ extract (WrapApply (Right a)) = a+ extract (WrapApply (Left fa)) = extract fa+ duplicate w@(WrapApply Right{}) = WrapApply (Right w)+ duplicate (WrapApply (Left fa)) = WrapApply (Left (extend (WrapApply . Left) fa))++instance ComonadApply f => ComonadApply (WrappedApply f)+ -- | A variant of '<.>' with the arguments reversed.-(<..>) :: ComonadZip w => w a -> w (a -> b) -> w b-(<..>) = liftW2 (flip id)+(<..>) :: FunctorApply w => w a -> w (a -> b) -> w b+(<..>) = liftF2 (flip id) {-# INLINE (<..>) #-} -- | Lift a binary function into a comonad with zipping-liftW2 :: ComonadZip w => (a -> b -> c) -> w a -> w b -> w c-liftW2 f a b = f <$> a <.> b+liftF2 :: FunctorApply w => (a -> b -> c) -> w a -> w b -> w c+liftF2 f a b = f <$> a <.> b+{-# INLINE liftF2 #-}++-- | Lift a ternary function into a comonad with zipping+liftF3 :: FunctorApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d+liftF3 f a b c = f <$> a <.> b <.> c+{-# INLINE liftF3 #-}++{- | ++A strong lax symmetric semi-monoidal comonad. As such an instance of +'ComonadApply' is required to satisfy:++> extract (a <.> b) = extract a (extract b)++This class is based on ComonadZip from \"The Essence of Dataflow Programming\" +by Tarmo Uustalu and Varmo Vene, but adapted to fit the programming style of+Control.Applicative. 'Applicative' can be seen as a similar law over and above +FunctorApply that:++> pure (a b) = pure a <.> pure b++-}++class (Comonad w, FunctorApply w) => ComonadApply w+-- | Only requires a Semigroup, but no such class exists+instance Monoid m => ComonadApply ((,)m)+-- | Only requires a Semigroup, but no such class exists+instance Monoid m => ComonadApply ((->)m)+instance ComonadApply Identity+instance ComonadApply w => ComonadApply (IdentityT w)++-- | Lift a binary function into a comonad with zipping+liftW2 :: ComonadApply w => (a -> b -> c) -> w a -> w b -> w c+liftW2 = liftF2 {-# INLINE liftW2 #-} -- | Lift a ternary function into a comonad with zipping-liftW3 :: ComonadZip w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d-liftW3 f a b c = f <$> a <.> b <.> c+liftW3 :: ComonadApply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d+liftW3 = liftF3 {-# INLINE liftW3 #-} -- | The 'Cokleisli' 'Arrow's of a given 'Comonad' newtype Cokleisli w a b = Cokleisli { runCokleisli :: w a -> b } +instance Comonad w => Category (Cokleisli w) where+ id = Cokleisli extract+ Cokleisli f . Cokleisli g = Cokleisli (f =<= g)+ instance Comonad w => Arrow (Cokleisli w) where arr f = Cokleisli (f . extract) first f = f *** id@@ -233,46 +367,28 @@ Cokleisli f *** Cokleisli g = Cokleisli (f . fmap fst &&& g . fmap snd) Cokleisli f &&& Cokleisli g = Cokleisli (f &&& g) -instance Comonad w => Category (Cokleisli w) where- id = Cokleisli extract- Cokleisli f . Cokleisli g = Cokleisli (f =<= g)- instance Comonad w => ArrowApply (Cokleisli w) where app = Cokleisli $ \w -> runCokleisli (fst (extract w)) (snd <$> w) instance Comonad w => ArrowChoice (Cokleisli w) where left = leftApp -instance ComonadZip d => ArrowLoop (Cokleisli d) where+instance ComonadApply w => ArrowLoop (Cokleisli w) where loop (Cokleisli f) = Cokleisli (fst . wfix . extend f') where f' wa wb = f ((,) <$> wa <.> (snd <$> wb)) +-- Cokleisli arrows are actually just a special case of a reader monad:+ instance Functor (Cokleisli w a) where fmap f (Cokleisli g) = Cokleisli (f . g) -instance Monad (Cokleisli w a) where- return a = Cokleisli (const a)- Cokleisli k >>= f = Cokleisli $ \w -> runCokleisli (f (k w)) w--{- $naming--The functions in this library use the following naming conventions, based-on those of Control.Monad.--* A postfix \'@W@\' always stands for a function in the Cokleisli category:- The monad type constructor @w@ is added to function results- (modulo currying) and nowhere else. So, for example, --> filter :: (a -> Bool) -> [a] -> [a]-> filterW :: Comonad w => (w a -> Bool) -> w [a] -> [a]--* A prefix \'@w@\' generalizes an existing function to a comonadic form.- Thus, for example: --> fix :: (a -> a) -> a-> wfix :: w (w a -> a) -> a+instance FunctorApply (Cokleisli w a) where+ Cokleisli f <.> Cokleisli a = Cokleisli (\w -> (f w) (a w)) -When ambiguous, consistency with existing Control.Monad combinator naming -supercedes these rules (e.g. 'liftW')+instance Applicative (Cokleisli w a) where+ pure = Cokleisli . const+ Cokleisli f <*> Cokleisli a = Cokleisli (\w -> (f w) (a w)) --}+instance Monad (Cokleisli w a) where+ return = Cokleisli . const+ Cokleisli k >>= f = Cokleisli $ \w -> runCokleisli (f (k w)) w
comonad.cabal view
@@ -1,6 +1,6 @@ name: comonad category: Control, Comonads-version: 0.3.0+version: 0.4.0 license: BSD3 cabal-version: >= 1.2 license-file: LICENSE