comonad (empty) → 0.1.0
raw patch · 4 files changed
+341/−0 lines, 4 filesdep +basedep +transformerssetup-changed
Dependencies added: base, transformers
Files
- Control/Comonad.hs +279/−0
- LICENSE +31/−0
- Setup.lhs +7/−0
- comonad.cabal +24/−0
+ Control/Comonad.hs view
@@ -0,0 +1,279 @@+-----------------------------------------------------------------------------+-- |+-- Module : Control.Comonad+-- Copyright : (C) 2008-2011 Edward Kmett,+-- (C) 2004 Dave Menendez+-- License : BSD-style (see the file LICENSE)+--+-- Maintainer : Edward Kmett <ekmett@gmail.com>+-- Stability : provisional+-- Portability : portable+--+-- A 'Comonad' is the categorical dual of a 'Monad'.+----------------------------------------------------------------------------+module Control.Comonad+ ( + -- * Functor and Comonad+ Functor(..)+ , Comonad(..)+ , ComonadZip(..)+ , Cokleisli(..)+ -- * 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+ , (<..>) -- :: ComonadZip w => w a -> w (a -> b) -> w b++ -- * Fixed points and folds+ , wfix -- :: Comonad w => w (w a -> a) -> a+ , unfoldW -- :: Comonad w => (w b -> (a,b)) -> w b -> [a]++ -- ** Comonadic lifting + , liftW -- :: Comonad w => (a -> b) -> w a -> 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+ , wzip -- :: ComonadZip w => w a -> w b -> w (a, b)++ ) where++import Prelude hiding (id, (.))+import Control.Arrow+import Control.Category+import Data.Functor+import Data.Monoid+import Data.Functor.Identity+import Control.Monad.Trans.Identity++infixl 1 =>> +infixr 1 <<=, =<=, =>= +infixl 4 <.>, <., .>, <..>++{-|+There are two ways to define a comonad:++I. Provide definitions for 'fmap', 'extract', and 'duplicate'+satisfying these laws:++> extract . duplicate == id+> fmap extract . duplicate == id+> duplicate . duplicate == fmap duplicate . duplicate++II. Provide definitions for 'extract' and 'extend'+satisfying these laws:++> extend extract == id+> extract . extend f == f+> extend f . extend g == extend (f . extend g)++('fmap' cannot be defaulted, but a comonad which defines+'extend' may simply set 'fmap' equal to 'liftW'.)++A comonad providing definitions for 'extend' /and/ 'duplicate',+must also satisfy these laws:++> extend f == fmap f . duplicate+> duplicate == extend id+> fmap f == extend (f . extract)++(The first two are the defaults for 'extend' and 'duplicate',+and the third is the definition of 'liftW'.)+-}++class Functor w => Comonad w where+ extract:: w a -> a+ duplicate :: w a -> w (w a)+ 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.+liftW :: Comonad w => (a -> b) -> w a -> w b+liftW f = extend (f . extract)+{-# INLINE liftW #-}++-- | 'extend' with the arguments swapped. Dual to '>>=' for a 'Monad'.+(=>>) :: Comonad w => w a -> (w a -> b) -> w b+(=>>) = flip extend+{-# INLINE (=>>) #-}++-- | 'extend' in operator form +(<<=) :: Comonad w => (w a -> b) -> w a -> w b+(<<=) = extend+{-# INLINE (<<=) #-}++-- | Right-to-left Cokleisli composition +(=<=) :: Comonad w => (w b -> c) -> (w a -> b) -> w a -> c+f =<= g = f . extend g+{-# INLINE (=<=) #-}++-- | Left-to-right Cokleisli composition+(=>=) :: Comonad w => (w a -> b) -> (w b -> c) -> w a -> c+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 directly avoiding the wart of orphan instances.++instance Comonad ((,)e) where+ extract = snd+ duplicate ~(e,a) = (e,(e,a))++instance Monoid m => Comonad ((->)m) where+ extract f = f mempty+ 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+ extract = runIdentity+ extend f = Identity . f + duplicate = Identity++-- Provided to avoid an orphan instance. Not proposed to standardize. +-- If Comonad moved to base, consider moving instance into transformers?+instance Comonad w => Comonad (IdentityT w) where+ extract = extract . runIdentityT+ extend f (IdentityT m) = IdentityT (extend (f . IdentityT) m)++{- | ++As a symmetric semi-monoidal comonad, an instance of ComonadZip is required to satisfy:++> extract (wzip a b) = (extract a, extract b)++By extension, the following law must also hold:++> extract (a <.> b) = extract a (extract b)++Minimum definition: '<.>'++Based on the ComonadZip from "The Essence of Dataflow Programming" +by Tarmo Uustalu and Varmo Vene, but adapted to fit the conventions of +Control.Monad and to provide a similar programming style to +that of Control.Applicative. ++-}+class Comonad w => ComonadZip w where+ -- | + -- > (<.>) = liftW2 id+ (<.>) :: w (a -> b) -> w a -> w b++ -- |+ -- > (.>) = liftW2 (const id)+ (.>) :: w a -> w b -> w b+ (.>) = liftW2 (const id)++ -- |+ -- > (<.) = liftW2 const+ (<.) :: w a -> w b -> w a+ (<.) = liftW2 const+ +instance Monoid m => ComonadZip ((,)m) where+ ~(m, a) <.> ~(n, b) = (m `mappend` n, a b)++instance Monoid m => ComonadZip ((->)m) where+ g <.> h = \m -> (g m) (h m)++instance ComonadZip Identity where+ Identity a <.> Identity b = Identity (a b)++instance ComonadZip w => ComonadZip (IdentityT w) where+ IdentityT wa <.> IdentityT wb = IdentityT (wa <.> wb)++(<..>) :: ComonadZip w => w a -> w (a -> b) -> w b+(<..>) = liftW2 (flip ($))+{-# INLINE (<..>) #-}++-- |+-- > wzip wa wb = (,) <$> wa <.> wb+-- > wzip = liftW2 (,) +-- +-- Called 'czip' in "Essence of Dataflow Programming"+wzip :: ComonadZip w => w a -> w b -> w (a, b)+wzip = liftW2 (,)+{-# INLINE wzip #-}++liftW2 :: ComonadZip w => (a -> b -> c) -> w a -> w b -> w c+liftW2 f a b = f <$> a <.> b+{-# INLINE liftW2 #-}++liftW3 :: ComonadZip w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d+liftW3 f a b c = f <$> a <.> b <.> c+{-# INLINE liftW3 #-}+++-- | The 'Cokleisli' 'Arrow's of a given 'Comonad'+newtype Cokleisli w a b = Cokleisli { runCokleisli :: w a -> b }++instance Comonad w => Arrow (Cokleisli w) where+ arr f = Cokleisli (f . extract)+ first f = f *** id+ second f = id *** f+ 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+ loop (Cokleisli f) = Cokleisli (fst . wfix . extend f') where + f' wa = f . wzip wa . fmap snd++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++When ambiguous, consistency with existing Control.Monad combinators supercedes other naming considerations.++-}
+ LICENSE view
@@ -0,0 +1,31 @@+Copyright 2008-2011 Edward Kmett+Copyright 2004-2008 Dave Menendez++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:++1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++3. Neither the name of the author nor the names of his contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,7 @@+#!/usr/bin/runhaskell+> module Main (main) where++> import Distribution.Simple++> main :: IO ()+> main = defaultMain
+ comonad.cabal view
@@ -0,0 +1,24 @@+name: comonad+category: Control, Comonads+version: 0.1.0+license: BSD3+cabal-version: >= 1.2+license-file: LICENSE+author: Edward A. Kmett+maintainer: Edward A. Kmett <ekmett@gmail.com>+stability: provisional+homepage: http://comonad.com/reader/+copyright: Copyright (C) 2008-2011 Edward A. Kmett, Copyright (C) 2004-2008 Dave Menendez+synopsis: Haskell 98 comonads+description: Haskell 98 comonads+build-type: Simple++library+ build-depends: + base > 4 && < 4.3,+ transformers >= 0.2.0 && < 0.3++ exposed-modules:+ Control.Comonad++ ghc-options: -Wall