TypeCompose (empty) → 0.0
raw patch · 9 files changed
+316/−0 lines, 9 filesdep +basedep +mtlbuild-type:Customsetup-changed
Dependencies added: base, mtl
Files
- CHANGES +1/−0
- Makefile +7/−0
- README +15/−0
- Setup.lhs +3/−0
- TODO +0/−0
- TypeCompose.cabal +34/−0
- src/Control/Compose.hs +133/−0
- src/Control/DataDriven.hs +90/−0
- src/Control/Instances.hs +33/−0
+ CHANGES view
@@ -0,0 +1,1 @@+
+ Makefile view
@@ -0,0 +1,7 @@+# For special configuration, especially for docs. Otherwise see README.++haddock-interfaces=\+ http://haskell.org/ghc/docs/latest/html/libraries/base,c:/ghc/ghc-6.6/doc/html/libraries/base/base.haddock \+ http://haskell.org/ghc/docs/latest/html/libraries/mtl,c:/ghc/ghc-6.6/doc/html/libraries/mtl/mtl.haddock \++include ../my-cabal-make.inc
+ README view
@@ -0,0 +1,15 @@+TypeCompose provides some classes & instances for forms of type+composition. It also includes a very simple implementation of data-driven+computation. See the description and link to documentation:++ http://haskell.org/haskellwiki/TypeCompose++Please share any comments & suggestions on the discussion (talk) page+there.++You can configure, build, and install all in the usual way with Cabal+commands.++ runhaskell Setup.lhs configure+ runhaskell Setup.lhs build+ runhaskell Setup.lhs install
+ Setup.lhs view
@@ -0,0 +1,3 @@+#!/usr/bin/env runhaskell +> import Distribution.Simple +> main = defaultMain
+ TODO view
+ TypeCompose.cabal view
@@ -0,0 +1,34 @@+Name: TypeCompose+Version: 0.0+Synopsis: Type composition classes & instances+Category: Composition, Control+Description:+ TypeCompose provides some classes & instances for forms of type+ composition. Bonus: a very simple implementation of data-driven+ computation.+ .+ See also+ .+ * The project wiki page: <http://haskell.org/haskellwiki/TypeCompose>+ .+ * Use of TypeCompose in Phooey: <http://haskell.org/haskellwiki/Phooey>+ .+ The module documentation pages have links to colorized source code and+ to wiki pages where you can read and contribute /user comments/. Enjoy!+ .+ © 2007 by Conal Elliott; BSD3 license.+Author: Conal Elliott +Maintainer: conal@conal.net+Homepage: http://haskell.org/haskellwiki/TypeCompose+Copyright: (c) 2007 by Conal Elliott+License: BSD3+Stability: provisional+Hs-Source-Dirs: src+Extensions: +Build-Depends: base, mtl+Exposed-Modules: + Control.Instances+ Control.Compose+ Control.DataDriven+Extra-Source-Files:+ghc-options: -O -Wall
+ src/Control/Compose.hs view
@@ -0,0 +1,133 @@+{-# OPTIONS -fglasgow-exts #-}++----------------------------------------------------------------------+-- |+-- Module : Control.Compose+-- Copyright : (c) Conal Elliott 2007+-- License : LGPL+-- +-- Maintainer : conal@conal.net+-- Stability : experimental+-- Portability : portable+-- +-- Various type constructor compositions and instances for them.+-- References:+-- [1] \"Applicative Programming with Effects\"+-- <http://www.soi.city.ac.uk/~ross/papers/Applicative.html>+----------------------------------------------------------------------++module Control.Compose+ ( Cofunctor(..)+ , Compose(..), onComp+ , StaticArrow(..)+ , Flip(..)+ , ArrowAp(..)+ , App(..)+ ) where++import Control.Applicative+import Control.Arrow hiding (pure)+import Data.Monoid++-- | Often useful for /acceptors/ (consumers, sinks) of values.+class Cofunctor acc where+ cofmap :: (a -> b) -> (acc b -> acc a)+++-- | Composition of type constructors: unary & unary. Called \"g . f\" in+-- [1], section 5, but GHC won't parse that, nor will it parse any infix+-- type operators in an export list. Haddock won't parse any type infixes+-- at all.+newtype Compose g f a = Comp { unComp :: g (f a) }++-- | Apply a function within the 'Comp' constructor.+onComp :: (g (f a) -> g' (f' a')) -> ((Compose g f) a -> (Compose g' f') a')+onComp h = Comp . h . unComp++instance (Functor g, Functor f) => Functor (Compose g f) where+ fmap h (Comp gf) = Comp (fmap (fmap h) gf)++instance (Applicative g, Applicative f) => Applicative (Compose g f) where+ pure = Comp . pure . pure+ Comp getf <*> Comp getx = Comp (liftA2 (<*>) getf getx)++-- instance (Functor g, Cofunctor f) => Cofunctor (Compose g f) where+-- cofmap h (Comp gf) = Comp (fmap (cofmap h) gf)++-- Or this alternative. Having both yields "Duplicate instance+-- declarations".+instance (Cofunctor g, Functor f) => Cofunctor (Compose g f) where+ cofmap h (Comp gf) = Comp (cofmap (fmap h) gf)++++-- standard Monoid instance for Applicative applied to Monoid+instance (Applicative (Compose g f), Monoid a) => Monoid (Compose g f a) where+ { mempty = pure mempty; mappend = (*>) }++-- | Composition of type constructors: unary with binary.+newtype StaticArrow f (~>) a b = Static { unStatic :: f (a ~> b) }++instance (Applicative f, Arrow (~>)) => Arrow (StaticArrow f (~>)) where+ arr = Static . pure . arr+ Static g >>> Static h = Static (liftA2 (>>>) g h)+ first (Static g) = Static (liftA first g)++-- For instance, /\ a b. f (a -> m b) =~ StaticArrow f Kleisli m+++-- | Composition of type constructors: binary with unary.++newtype ArrowAp (~>) f a b = ArrowAp {unArrowAp :: f a ~> f b}++instance (Arrow (~>), Applicative f) => Arrow (ArrowAp (~>) f) where+ arr = ArrowAp . arr . liftA+ ArrowAp g >>> ArrowAp h = ArrowAp (g >>> h)+ first (ArrowAp a) =+ ArrowAp (arr splitA >>> first a >>> arr mergeA)++instance (ArrowLoop (~>), Applicative f) => ArrowLoop (ArrowAp (~>) f) where+ -- loop :: UI (b,d) (c,d) -> UI b c+ loop (ArrowAp k) =+ ArrowAp (loop (arr mergeA >>> k >>> arr splitA))++-- Wolfgang Jeltsch pointed out a problem with these definitions: 'splitA'+-- and 'mergeA' are not inverses. The definition of 'first', e.g.,+-- violates the \"extension\" law and causes repeated execution. Look for+-- a reformulation or a clarification of required properties of the+-- applicative functor @f@.+-- +-- See also "Arrows and Computation", which notes that the following type+-- is "almost an arrow" (http://www.soi.city.ac.uk/~ross/papers/fop.html).+-- +-- > newtype ListMap i o = LM ([i] -> [o])++mergeA :: Applicative f => (f a, f b) -> f (a,b)+mergeA ~(fa,fb) = liftA2 (,) fa fb++splitA :: Applicative f => f (a,b) -> (f a, f b)+splitA fab = (liftA fst fab, liftA snd fab)+++-- | Flip type arguments+newtype Flip (~>) b a = Flip (a ~> b)++instance Arrow (~>) => Cofunctor (Flip (~>) b) where+ cofmap h (Flip f) = Flip (arr h >>> f)+++-- | Type application+newtype App f a = App { unApp :: f a }++-- Example: App IO ()+instance (Applicative f, Monoid m) => Monoid (App f m) where+ mempty = App (pure mempty)+ App a `mappend` App b = App (a *> b)++{-+-- We can also drop the App constructor, but then we overlap with many+-- other instances, like [a].+instance (Applicative f, Monoid a) => Monoid (f a) where+ mempty = pure mempty+ mappend = (*>)+-}
+ src/Control/DataDriven.hs view
@@ -0,0 +1,90 @@+{-# OPTIONS -fglasgow-exts #-}++----------------------------------------------------------------------+-- |+-- Module : Control.DataDriven+-- Copyright : (c) Conal Elliott 2007+-- License : LGPL+-- +-- Maintainer : conal@conal.net+-- Stability : experimental+-- Portability : portable+-- +-- Data-driven computations+----------------------------------------------------------------------++module Control.DataDriven+ (+ -- * Plumbing for \"events\" and subscription + Sink, Updater, News+ -- * Data-driven computations+ , DataDrivenG, dd, mapSrc+ , DataDriven, runDD, joinDD+ ) where++import Control.Applicative+import Control.Monad (join)+import Control.Arrow (second)++import Data.Monoid++import Control.Compose+++{----------------------------------------------------------+ Plumbing for event publishing+----------------------------------------------------------}++-- | Sinks (consumers) of values+type Sink src a = a -> Updater src++-- | Updaters (actions)+type Updater src = src ()++-- | News publisher -- somewhere to register updaters to be executed+-- when events occur.+type News src = Sink src (Updater src)+++{----------------------------------------------------------+ Data-driven computations+----------------------------------------------------------}++-- | The general type of data-driven computations. Represented as a+-- /news/ publisher (@news@) and a source of new values (@src@). Clients+-- interested in the value subscribe to @news@ and extract a new value+-- from @src@ when notified that the value may have changed. When @news@+-- is a monoid and @src@ is an applicative functor, @DataDriven news src@+-- is an applicative functor also. The applicative property is very+-- convenient for composition. See the more specific type 'DataDriven'.++type DataDrivenG news src = Compose ((,) news) src++-- | Construct a data-driven computation from a subscription service+-- (@Monoid@) and a value source subscriber (@Applicative@).+dd :: news -> src a -> DataDrivenG news src a+dd = curry Comp++-- | Modify the source part of a 'DataDriven' computation.+mapSrc :: (src a -> src b) -> (DataDrivenG news src a -> DataDrivenG news src b)+mapSrc f = onComp (second f)+++-- | Data driven with news publisher+type DataDriven src = DataDrivenG (News src) src+++-- | Run a unit-valued 'DataDriven' computation. Causes the source to be+-- executed /and/ registered with the subscriber.+runDD :: (Monoid (Updater src), Applicative src)+ => DataDriven src () -> Updater src+runDD (Comp (news,src)) = news src `mappend` src++-- | Apply 'join' to a source+joinDD :: Monad src => DataDriven src (src a) -> DataDriven src a+joinDD = mapSrc join++-- runDDJoin :: (Monad src, Applicative src, Monoid (Updater src))+-- => DataDriven src (Updater src) -> Updater src+-- runDDJoin = runDD . joinDD+
+ src/Control/Instances.hs view
@@ -0,0 +1,33 @@+{-# OPTIONS #-} + +---------------------------------------------------------------------- +-- | +-- Module : Control.Instances +-- Copyright : (c) Conal Elliott 2007 +-- License : LGPL +-- +-- Maintainer : conal@conal.net +-- Stability : experimental +-- Portability : portable +-- +-- Some (orphan) instances that belong elsewhere (where they wouldn't be orphans). +-- Add the following line to get these instances +-- +-- > import Control.Instances () +-- +---------------------------------------------------------------------- + +module Control.Instances () where + +import Data.Monoid +import Control.Applicative +import Control.Monad.Reader +import Control.Monad + + +-- Standard instance: Applicative functor applied to monoid +instance Monoid a => Monoid (IO a) where { mempty = pure mempty; mappend = (*>) } + +-- standard Applicative instance for Monad +instance Monad m => Applicative (ReaderT r m) where { pure = return; (<*>) = ap } +