effect-monad (empty) → 0.6
raw patch · 38 files changed
+1461/−0 lines, 38 filesdep +basedep +ghc-primdep +type-level-setssetup-changed
Dependencies added: base, ghc-prim, type-level-sets
Files
- LICENSE +26/−0
- Setup.hs +6/−0
- effect-monad.cabal +52/−0
- examples/ArrayReader.hs +50/−0
- examples/Counter.hs +75/−0
- examples/CounterNat.hs +58/−0
- examples/ImplicitP.hs +34/−0
- examples/Maybe.hs +12/−0
- examples/Monad.hs +12/−0
- examples/Problem1.hs +30/−0
- examples/ReadOnceReader.hs +30/−0
- examples/Reader.hs +40/−0
- examples/Solution1-alt.hs +22/−0
- examples/Solution1.hs +47/−0
- examples/Solution2.hs +22/−0
- examples/State.hs +26/−0
- examples/StencilSpecs.hs +57/−0
- examples/Update.hs +10/−0
- examples/WriteOnceWriter.hs +9/−0
- examples/Writer.hs +46/−0
- examples/WriterM.hs +17/−0
- src/Control/Coeffect.hs +42/−0
- src/Control/Coeffect/Coreader.hs +33/−0
- src/Control/Effect.hs +37/−0
- src/Control/Effect/Cond.hs +22/−0
- src/Control/Effect/Counter.hs +38/−0
- src/Control/Effect/CounterNat.hs +28/−0
- src/Control/Effect/Helpers/List.hs +26/−0
- src/Control/Effect/Maybe.hs +63/−0
- src/Control/Effect/Monad.hs +32/−0
- src/Control/Effect/Parameterised.hs +25/−0
- src/Control/Effect/ReadOnceReader.hs +39/−0
- src/Control/Effect/Reader.hs +48/−0
- src/Control/Effect/State.hs +180/−0
- src/Control/Effect/Update.hs +36/−0
- src/Control/Effect/Vector.hs +42/−0
- src/Control/Effect/WriteOnceWriter.hs +32/−0
- src/Control/Effect/Writer.hs +57/−0
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2014, Dominic Orchard++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * 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.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"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 COPYRIGHT+OWNER 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.hs view
@@ -0,0 +1,6 @@+module Main (main) where++import Distribution.Simple++main :: IO ()+main = defaultMain
+ effect-monad.cabal view
@@ -0,0 +1,52 @@+name: effect-monad+version: 0.6+synopsis: Embeds effect systems into Haskell using parameteric effect monads+description: + Provides the 'parametric effect monad' structure to Haskell with a number of analogous of familiar monads (Reader, Writer, State, Maybe, Counter, Update) and a wrapper over normal monads (Control.Effect.Monad). This provides a way to embed effect systems into Haskell. For more information see with paper \"Embedding effect systems in Haskell\" by Orchard and Petricek <http://www.cl.cam.ac.uk/~dao29/publ/haskell14-effects.pdf> (Haskell, 2014) and the examples in <https://github.com/dorchard/effect-monad/tree/master/examples>. + .+ (note, this package was previously called 'ixmonad' until September 2014). ++license: BSD3+license-file: LICENSE+category: Control, Monads+copyright: 2013-14 University of Cambridge+author: Dominic Orchard+maintainer: Dominic Orchard+stability: experimental+build-type: Simple+cabal-version: >= 1.6+tested-with: GHC == 7.8.2++extra-source-files: examples/*.hs+++source-repository head+ type: git+ location: https://github.com/dorchard/effect-monad++library+ hs-source-dirs: src+++ exposed-modules: Control.Coeffect+ Control.Coeffect.Coreader+ Control.Effect+ Control.Effect.Cond+ Control.Effect.Counter+ Control.Effect.CounterNat+ Control.Effect.Maybe+ Control.Effect.Monad+ Control.Effect.Parameterised+ Control.Effect.Reader+ Control.Effect.ReadOnceReader+ Control.Effect.State+ Control.Effect.Update+ Control.Effect.Vector+ Control.Effect.WriteOnceWriter+ Control.Effect.Writer+ Control.Effect.Helpers.List+ + build-depends: base < 5,+ ghc-prim,+ type-level-sets >= 0.5+
+ examples/ArrayReader.hs view
@@ -0,0 +1,50 @@+{-# LANGUAGE TypeFamilies, GADTs, MultiParamTypeClasses, FlexibleInstances,+ FlexibleContexts, DataKinds, UndecidableInstances, ScopedTypeVariables #-}++module ArrayReader where ++import GHC.TypeLits +import Data.Array+import Prelude hiding (Monad(..)) ++import Data.Proxy+import Control.Effect+import Data.Type.Set++-- Array with a cursor+data CArray (x::[*]) a = MkA (Array Int a, Int) ++-- Computations from 'a' to 'b' with an array parameter+data Stencil a (r::[*]) b = Stencil (CArray r a -> b)++-- Get the nth index from the array, relative to the 'cursor'+ix :: (ToValue (IntT x) Int) => IntT x -> Stencil a '[IntT x] a+ix n = Stencil (\(MkA (a, cursor)) -> a ! (cursor + toValue n))++instance Effect (Stencil a) where+ type Inv (Stencil a) s t = ()+ type Plus (Stencil a) s t = Union s t -- append specs+ type Unit (Stencil a) = '[] -- empty spec++ (Stencil f) >>= k = + Stencil (\(MkA a) -> let (Stencil f') = k (f (MkA a))+ in f' (MkA a))+ return a = Stencil (\_ -> a)++data Sign n = Pos n | Neg n+data IntT (n :: Sign Nat) = IntT++class ToValue t t' where+ toValue :: t -> t'++instance (KnownNat n) => ToValue (IntT (Pos (n :: Nat))) Int where+ toValue _ = fromInteger $ natVal (Proxy :: (Proxy n))++instance (KnownNat n) => ToValue (IntT (Neg (n :: Nat))) Int where+ toValue _ = - (fromInteger $ natVal (Proxy :: (Proxy n)))++type instance Cmp (IntT (Pos n)) (IntT (Pos m)) = CmpNat n m+type instance Cmp (IntT (Neg n)) (IntT (Neg m)) = CmpNat n m+type instance Cmp (IntT (Pos n)) (IntT (Neg m)) = GT+type instance Cmp (IntT (Neg n)) (IntT (Pos m)) = LT+
+ examples/Counter.hs view
@@ -0,0 +1,75 @@+{-# LANGUAGE RebindableSyntax, EmptyDataDecls, GADTs, TypeFamilies, UndecidableInstances, MultiParamTypeClasses, TypeOperators #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.Counter++import Debug.Trace++{- ++The 'Counter' indexed monad is useful for counting computations+of a particular kind (e.g., counting number of calls to a websocket)+or estimating resource usage (e.g., a websocket call is more expensive+than a disk write). ++By default, zero counts are tracked, e.g., ++-}++foo :: Counter Z Int+foo = do x <- return 2+ y <- return 4+ return (x + y)++{- the 'tick' function lifts a value to be counted once, e.g. -}++-- foo2 :: Counter (S Z) Int+foo2 = do x <- tick 2+ y <- return 3+ return (x * y)++{- This can be used for other cool things, like proving that 'map' has + linear complexity of 'map' at the type-level! ++For this we need sized lists:+-}++data Vector n a where+ Nil :: Vector Z a+ Cons :: a -> Vector n a -> Vector (S n) a++type family n :* m +type instance Z :* m = Z+type instance (S n) :* m = m :+ (n :* m)++{- map' is then defined as follows -}++map' :: (a -> Counter t b) -> Vector n a -> Counter (n :* t) (Vector n b)+map' f Nil = return Nil+map' f (Cons x xs) = do x' <- f x+ xs' <- map' f xs+ return (Cons x' xs')++{- The types show us that if the function counts 't' things, then applying 'map'+to an n-vector counts 'tn' things -}++{- Example: web socket calls- how many do we do per instances #-}++call :: Int -> Counter (S Z) ()+call = undefined++singleCall = map' call (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil))))++doubleCall x = map' (\n -> do {a <- call n; b <- call n; return ()}) x++doubleCallExample = doubleCall (Cons 1 (Cons 2 (Cons 3 (Cons 4 Nil))))++{- are we definitely linear in the number of elements, even if we have closed over the vector? -}++class LT n m+instance LT Z (S n)+instance LT n m => LT (S n) (S m)++lineraMap :: LT t n => (a -> Counter t b) -> Vector n a -> Counter (n :* t) (Vector n b)+lineraMap = map'
+ examples/CounterNat.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE RebindableSyntax, TypeOperators, DataKinds, KindSignatures, GADTs, TypeFamilies, UndecidableInstances #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.CounterNat++import GHC.TypeLits++import Debug.Trace++{- ++The 'Counter' indexed monad is useful for counting computations+of a particular kind (e.g., counting number of calls to a websocket)+or estimating resource usage (e.g., a websocket call is more expensive+than a disk write). ++By default, zero counts are tracked, e.g., -}++foo :: Counter 0 Int+foo = do x <- return 2+ y <- return 4+ return (x + y)++{- the 'one' function lifts a value to be counted once, e.g. -}++-- foo2 :: Counter (S Z) Int+foo2 = do x <- tick 2+ y <- return 3+ return (x * y) ++{- This can be used for other cool things, like proving that 'map' has + linear complexity of 'map' at the type-level! ++For this we need sized lists:+-}+++data Vector (n :: Nat) a where+ Nil :: Vector 0 a+ Cons :: a -> Vector n a -> Vector (n + 1) a++type family (n :: Nat) :* (m :: Nat) :: Nat where+ 0 :* m = 0+ n :* m = m + ((n - 1) :* m)++{- map' is then defined as follows -}++{- CAN'T TYPE CHECK, see Counter.hs ++map' :: (a -> Counter t b) -> Vector n a -> Counter (n :* t) (Vector n b)+map' f Nil = return Nil+map' f (Cons x xs) = do x' <- f x+ xs' <- map' f xs+ return (Cons x' xs')++-}+
+ examples/ImplicitP.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE ImplicitParams, DataKinds, RebindableSyntax, TypeOperators #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.Reader++foo :: (Num a, ?x :: a, ?y :: a) => a -> a+foo z = ?x + ?y++fooM :: (Num a) => a -> Reader '["?x" :-> a, "?y" :-> a] a+fooM z = do x <- ask (Var::(Var "?x"))+ y <- ask (Var::(Var "?y"))+ return (x + y + z)++foo' :: (Num a, ?y :: a) => a -> a+foo' = let ?x = 42+ in \z -> ?x + ?y + z++fooM' :: Num a => Reader '["?x" :-> a] (a -> Reader '["?y" :-> a] a)+fooM' = merge (\z -> do x <- ask (Var::(Var "?x"))+ y <- ask (Var::(Var "?y"))+ return (x + y + z))++with f x = runReader f x++fooM'' = fooM' `with` (Ext (Var :-> 42) Empty)++sum2 :: Num a => a -> Reader '["?y" :-> a] a+sum2 = let x = (Ext ((Var::(Var "?x")) :-> 42) Empty) + in runReader (merge (\z -> do x <- ask (Var::(Var "?x"))+ y <- ask (Var::(Var "?y"))+ return (x + y + z))) x++
+ examples/Maybe.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE RebindableSyntax, NoMonomorphismRestriction #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.Cond+import Control.Effect.Maybe++headM x = ifM (x == []) (INothing) (IJust (head x))++foo x y = do x' <- headM x+ y' <- headM y+ return [x', y']
+ examples/Monad.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE TypeFamilies, RebindableSyntax #-}++import Control.Effect+import Control.Effect.Monad+import Prelude hiding (Monad(..)) ++putStrLn' = Wrap . putStrLn++printer = do putStrLn' "Hello"+ putStrLn' "I am really regular IO monad"+ putStrLn' "hiding as the free indexed monad version"+ return ()
+ examples/Problem1.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE NoMonomorphismRestriction, FlexibleContexts #-}++import Control.Monad.State.Lazy++incSC :: (Monad m) => StateT Int m ()+incSC = do x <- get+ put (x + 1)++writeS :: (Monad m) => [a] -> StateT [a] m ()+writeS y = do x <- get+ put (x ++ y)++write :: (Monad m) => [a] -> StateT [a] (StateT Int m) ()+write x = do writeS x+ lift $ incSC++hellow = do write "hello"+ write " "+ write "world"++runHellow = runStateT (runStateT hellow "") 0++-- prog2 :: (Monad m) => StateT Int (StateT String (StateT Int (StateT String m))) ()++hellowCount = do hellow+ lift $ lift $ incSC++runHellowCount = runStateT (runStateT (runStateT hellowCount "") 0) 1++
+ examples/ReadOnceReader.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE RebindableSyntax, NoMonomorphismRestriction #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.Cond+import Control.Effect.ReadOnceReader++foo = do x <- ask+ y <- ask + return ("Name " ++ x ++ " age " ++ (show y))++--foo_eval = foo (HCons' 'a' (HCons' "bc" HNil'))++foo2 = do x <- ask + y <- ask+ xs <- ask+ return (x : (y : xs))++foo2' = do x <- ask + xs' <- do y <- ask+ xs <- ask+ return (y:xs)+ return (x : xs')++foo2_eval foo2 = runReader foo2 (Cons 'a' (Cons 'b' (Cons "c" Nil)))++foo3 = do x <- ask+ ifM x ask (return 0)++foo3_eval = runReader foo3 (Cons False (Cons 42 Nil))
+ examples/Reader.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE RebindableSyntax, NoMonomorphismRestriction, DataKinds, TypeOperators, + FlexibleContexts, ConstraintKinds #-}+import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.Reader++import GHC.TypeLits++{- Examples -}++-- foo :: Reader '["x" :-> a, "xs" :-> [a]] [a]+foo = do x <- ask (Var::(Var "x"))+ xs <- ask (Var::(Var "xs"))+ x' <- ask (Var::(Var "x"))+ return (x:x':xs)++init1 = Ext (Var :-> 1) (Ext (Var :-> [2, 3]) Empty)+runFoo = runReader foo init1++-- Examples with subeffecting (need to refine the types a bit to 'run')++bar :: (Subset '["x" :-> Int, "xs" :-> [Int]] t) => Reader t [Int]+bar = sub foo++init2 :: Set '["x" :-> Int, "xs" :-> [Int], "z" :-> a]+init2 = Ext (Var :-> 1) (Ext (Var :-> [2, 3]) (Ext (Var :-> undefined) Empty))+runBar = runReader bar init2++-- Note: GHC currently has trouble with+--init2a = asSet (append init1 (Ext (Var :-> undefined) Empty))++{-+foo_b = do x <- ask (Var::(Var "x"))+ y <- ask (Var::(Var "x"))+ return (not x,not y)++foo_b = +-}++-- runFoob = runReader foo_b (Ext (Var :-> 1) (Ext (Var :-> [1,2,3]) Empty))
+ examples/Solution1-alt.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}++import Control.Monad.State.Lazy++class Monad m => Streaming a m where+ writeS :: [a] -> m ()++class Monad m => Counting m where+ incC :: m ()++-- write :: (Streaming a m, Counting m) => [a] -> m ()+write x = do { writeS x; incC }++instance Monad m => Streaming a (StateT [a] m) where+ writeS y = do x <- get+ put (x ++ y)++instance Monad m => Counting (StateT Int m) where+ incC = do x <- get+ put (x + 1)++foo = runStateT 0 $ runStateT "" $ write "message"
+ examples/Solution1.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE FlexibleContexts, DataKinds, TypeOperators, + RebindableSyntax, FlexibleInstances #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.State++c1_var = Var::(Var "c1")+c2_var = Var::(Var "c2")+o_var = Var::(Var "out")++instance Show (Var "out") where+ show _ = "out"++instance Show (Var "c1") where+ show _ = "c1"++instance Show (Var "c2") where+ show _ = "c2"++incC :: Var v -> State '[v :-> Int :! RW] ()+incC var = do x <- get var+ put var (x + 1)++writeS :: [a] -> State '["out" :-> [a] :! RW] ()+writeS y = do x <- get o_var+ put o_var (x ++ y)++write :: [a] -> State '["c1" :-> Int :! RW, "out" :-> [a] :! RW] ()+write x = do writeS x+ incC c1_var++initState0 = Ext (c1_var :-> ((0::Int) :! Eff)) (Ext (o_var :-> ("" :! Eff)) Empty)+runWrite = runState (write "hello") initState0++hellow = do write "hello"+ write " "+ write "world"++initState = Ext (c1_var :-> ((0::Int) :! Eff)) (Ext (o_var :-> ("" :! Eff)) Empty)+runHellow = runState hellow initState++hellowCount = do hellow+ incC c2_var++initState' = Ext (c1_var :-> ((0::Int) :! Eff)) (Ext (c2_var :-> ((1::Int) :! Eff)) (Ext (o_var :-> ("" :! Eff)) Empty))+runHellowCount = runState hellowCount initState'
+ examples/Solution2.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE RebindableSyntax, TypeOperators, DataKinds, KindSignatures, FlexibleInstances, + ConstraintKinds, FlexibleContexts, TypeFamilies #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Data.Type.Set+import Control.Effect.State+import GHC.Conc.Sync++parMap :: (IsSet f, StateSet f, Writes f ~ '[]) => (a -> State f b) -> [a] -> State f [b] +-- parMap k [] = sub (return [])+parMap k [x] = do y <- k x+ return [y]+parMap k (x:xs) = do y <- k x+ ys <- parMap k xs+ return (y : ys)+++parMap2 :: (StateSet f, Writes f ~ '[]) => (a -> State f b) -> [a] -> State f [b] +parMap2 k [] = sub (return [])+parMap2 k (x:xs) = do (y, ys) <- (k x) `par` parMap2 k xs+ return (y : ys)
+ examples/State.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE DataKinds, RebindableSyntax, TypeOperators, FlexibleInstances #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.State++x_var = Var::(Var "x")+y_var = Var::(Var "y")++{- Computation with a read effect on variable "x" and a read-write (update) effect on variable "y" -}+foo :: State '["x" :-> Int :! R, "y" :-> [Int] :! RW] [Int]+foo = do x <- get x_var+ y <- get y_var+ put y_var (x:y)+ z <- get y_var+ return (x:z)++foo_run = runState foo (Ext (x_var :-> (1 :! Eff)) (Ext (y_var :-> ([2,3] :! Eff)) Empty))++foo2 :: State '["x" :-> Int :! RW] Int+foo2 = do x <- get x_var+ put x_var (x+1)+ return x++foo2_run = (runState foo2) (Ext (x_var :-> 10 :! Eff) Empty)+
+ examples/StencilSpecs.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE RebindableSyntax, GADTs, TypeFamilies, DataKinds, TypeOperators, UndecidableInstances #-}++import Prelude hiding (Monad(..))++import GHC.TypeLits hiding (Nat)+import Data.Type.Set+import Control.Effect+import ArrayReader++localMean :: (Num a, Fractional a) => Stencil a (Symmetrical 1) a+--localMean :: (Num a, Fractional a) => Stencil a '[IntT (Neg 1), IntT (Pos 0), IntT (Pos 1)] a+localMean = do a <- ix (IntT :: (IntT (Pos 0)))+ b <- ix (IntT :: (IntT (Pos 1)))+ c <- ix (IntT :: (IntT (Neg 1)))+ return $ (a + b + c) / 3.0++fooFwd :: Num a => Stencil a (Forward 2) a+fooFwd = do a <- ix (IntT :: (IntT (Pos 0)))+ b <- ix (IntT :: (IntT (Pos 1)))+ c <- ix (IntT :: (IntT (Pos 2)))+ return $ a + b + c++ {-+-- The following causes a type error as it violates the specification+-- of symmetry++fooSymBroken :: (Num a) => StencilM a (Symmetrical (S Z)) a a+fooSymBroken = StencilM $ do a <- ix (Pos Z)+ b <- ix (Pos (S Z))+ return $ a + b +-}++-- fooFwd has a 'forward' pattern to depth of 2++-- Specification definitions++-- Forward-oriented stencil specification++type Forward sten = AsSet ((IntT (Pos 0)) ': (ForwardP sten))++-- ForwardP excludes the zero point+type family ForwardP depth where+ ForwardP 0 = '[]+ ForwardP n = (IntT (Pos n)) ': (ForwardP (n - 1))+++-- Symmetrical stencils (derived from Forward and Backward stencils of the same depth)++type Symmetrical depth = AsSet ((IntT (Pos 0)) ': (Append (ForwardP depth) (BackwardP depth)))++-- Backward-oriented stencils++type Backward sten = AsSet ((IntT (Pos 0)) ': (BackwardP sten))++type family BackwardP depth where+ BackwardP 0 = '[]+ BackwardP n = (IntT (Neg n)) ': (BackwardP (n - 1))
+ examples/Update.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE RebindableSyntax, DataKinds #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.Update++foo :: Update (Just String) ()+foo = do put 42+ put "hello"+ return ()
+ examples/WriteOnceWriter.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE RebindableSyntax, NoMonomorphismRestriction #-}++import Prelude hiding (Monad(..))+import Control.Effect+import Control.Effect.WriteOnceWriter ++foo = do put 42+ put "hello"+ return ()
+ examples/Writer.hs view
@@ -0,0 +1,46 @@+{-# LANGUAGE DataKinds, KindSignatures, TypeOperators, RebindableSyntax, FlexibleInstances, + ConstraintKinds, FlexibleContexts, TypeFamilies, ScopedTypeVariables+ #-}++import Control.Effect+import Control.Effect.Writer++import Data.Monoid++import Prelude hiding (Monad(..))++instance Monoid Int where+ mappend = (+)+ mempty = 0++var_x = Var::(Var "x")+var_y = Var::(Var "y")++test :: Writer '["x" :-> Int, "y" :-> String] ()+test = do put var_x (42::Int)+ put var_y "hello"+ put var_x (58::Int)+ put var_y " world"++--test' :: forall a . (Monoid a, Num a) => a -> Writer '["x" :-> a, "y" :-> String] ()+test' (n::a) = do put var_x (42::a)+ put var_y "hello"+ put var_x (n::a)+ put var_y " world"++{-- Polymorphism test -}+test2 :: (IsSet f, Unionable f '["y" :-> String]) => + (Int -> Writer f t) -> Writer (Union f '["y" :-> String]) ()+test2 f = do f 3 + put var_y ". hi"++{-- Subeffecting test -}+test3 :: Writer '["x" :-> Int, "y" :-> String, "z" :-> Int] ()+test3 = sub (test2 test')++foo2 :: (IsSet f, Unionable f '["x" :-> Int, "y" :-> t], Num a) => + (a -> Writer f t) -> Writer (Union f '["x" :-> Int, "y" :-> t]) ()+foo2 f = do y <- f 3+ put var_x (42::Int)+ put var_y y+
+ examples/WriterM.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE FlexibleInstances #-}++import Data.Monoid++data Writer w a = Writer { runWriter :: (a, w) }++instance Monoid w => Monad (Writer w) where+ return a = Writer (a, mempty)+ (Writer (a, w)) >>= k = let (b, w') = runWriter (k a)+ in Writer (b, w `mappend` w')++instance Monad (Writer (Maybe a)) where+ return a = Writer (a, Nothing)+ (Writer (a, w)) >>= k = let (b, w') = runWriter (k a)+ in case w' of + Nothing -> Writer (b, w)+ Just w' -> Writer (b, Just w')
+ src/Control/Coeffect.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses #-}+{-# LANGUAGE ConstraintKinds, PolyKinds, ScopedTypeVariables, DataKinds #-}++module Control.Coeffect where ++import GHC.Prim++{- Coeffect parameterised comonad++Also called "indexed comonads". +For more details see "Coeffects: Unified static analysis of context-dependence"+by Petricek, Orchard, Mycroft: http://www.cl.cam.ac.uk/~dao29/publ/coeffects-icalp13.pdf++-}++{-| Specifies "parametric coeffect comonads" which are essentially comonads but+ annotated by a type-level monoid formed by 'Plus' and 'Unit' -}+class Coeffect (c :: k -> * -> *) where+ type Inv c (s :: k) (t :: k) :: Constraint+ type Inv c s t = ()++ type Unit c :: k + type Plus c (s :: k) (t :: k) :: k++ {-| Coeffect-parameterised version of 'extract', + annotated with the 'Unit m' effect, denoting pure contexts -}+ extract :: c (Unit c) a -> a++ {-| Coeffect-parameterise version of 'extend'.+ The two coeffec annotations 's' and 't' on its parameter computations+ get combined in the parameter computation by 'Plus' -}+ extend :: Inv c s t => (c t a -> b) -> c (Plus c s t) a -> c s b++{-| Zips two coeffecting computations together -}+class CoeffectZip (c :: k -> * -> *) where+ type Meet c (s :: k) (t :: k) :: k+ type CzipInv c (s :: k) (t :: k) :: Constraint+ czip :: CzipInv c s t => c s a -> c t b -> c (Meet c s t) (a, b)++{-| Specifies sub-coeffecting behaviour -}+class Subcoeffect (c :: k -> * -> *) s t where+ subco :: c s a -> c t a
+ src/Control/Coeffect/Coreader.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, GADTs, + ConstraintKinds, TypeOperators, DataKinds, UndecidableInstances #-}++module Control.Coeffect.Coreader where++import Control.Coeffect+import Data.Type.Set++{-| Provides 'reader monad'-like behaviour but as a comonad, using an indexed+ version of the product comonad -}+data IxCoreader s a = IxR { runCoreader :: (a, Set s) }++instance Coeffect IxCoreader where+ type Inv IxCoreader s t = (Unionable s t, Split s t (Union s t))++ type Unit IxCoreader = '[]+ type Plus IxCoreader s t = Union s t++ extract (IxR (x, Empty)) = x+ extend k (IxR (x, st)) = let (s, t) = split st+ in IxR (k (IxR (x, t)), s)++instance CoeffectZip IxCoreader where+ type Meet IxCoreader s t = Union s t+ type CzipInv IxCoreader s t = (Unionable s t)++ czip (IxR (a, s)) (IxR (b, t)) = IxR ((a, b), union s t)+++{-| 'ask' for the value of variable 'v', e.g., 'ask (Var::(Var "x"))' -}+ask :: Var v -> IxCoreader '[v :-> a] b -> a+ask _ = \(IxR (_, Ext (Var :-> a) Empty)) -> a+
+ src/Control/Effect.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE KindSignatures, TypeFamilies, ConstraintKinds, PolyKinds, MultiParamTypeClasses #-}++module Control.Effect where ++import Prelude hiding (Monad(..))+import GHC.Prim+++{-| Specifies "parametric effect monads" which are essentially monads but+ annotated by a type-level monoid formed by 'Plus' and 'Unit' -}+class Effect (m :: k -> * -> *) where++ {-| Effect of a trivially effectful computation |-}+ type Unit m :: k+ {-| Cominbing effects of two subcomputations |-}+ type Plus m (f :: k) (g :: k) :: k++ {-| 'Inv' provides a way to give instances of 'Effect' their own constraints for '>>=' -}+ type Inv m (f :: k) (g :: k) :: Constraint+ type Inv m f g = ()++ {-| Effect-parameterised version of 'return'. Annotated with the 'Unit m' effect, + denoting pure compuation -}+ return :: a -> m (Unit m) a++ {-| Effect-parameterise version of '>>=' (bind). Combines + two effect annotations 'f' and 'g' on its parameter computations into 'Plus' -}+ (>>=) :: (Inv m f g) => m f a -> (a -> m g b) -> m (Plus m f g) b++ (>>) :: (Inv m f g) => m f a -> m g b -> m (Plus m f g) b+ x >> y = x >>= (\_ -> y)+ +fail = undefined++{-| Specifies subeffecting behaviour -}+class Subeffect (m :: k -> * -> *) f g where+ sub :: m f a -> m g a
+ src/Control/Effect/Cond.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE TypeFamilies, ConstraintKinds, PolyKinds #-}++module Control.Effect.Cond where++import GHC.Prim++{-| Provides a conditional using an 'alternation' operation, as opposed to using+ 'Subeffect' -}++class Cond (m :: k -> * -> *) where+ type AltInv m (s :: k) (t :: k) :: Constraint+ type AltInv m s t = ()++ {-| Type family for describing how to combine effects of the two+ branches of an if -}+ type Alt m (s :: k) (t :: k) :: k ++ {-| Conditional on effectful operations -}+ ifM :: AltInv m s t => Bool -> m s a -> m t a -> m (Alt m s t) a++-- Related to indexed 'applicative' functors/idioms+-- which are indexed monoidal functors
+ src/Control/Effect/Counter.hs view
@@ -0,0 +1,38 @@+{-# LANGUAGE TypeFamilies, EmptyDataDecls, TypeOperators #-}++module Control.Effect.Counter(Z, S, Counter, tick, (:+)) where++import Control.Effect+import Prelude hiding (Monad(..))++{-| Provides a way to 'count' in the type-level with a monadic interface+ to sum up the individual counts of subcomputations -}++{-| Define type constructors for natural numbers -}+data Z+data S n++{-| The counter has no semantic meaning -}+data Counter n a = Counter { forget :: a }++{-| Type-level addition -}+type family n :+ m +type instance n :+ Z = n+type instance n :+ (S m) = S (n :+ m)++instance Effect Counter where+ type Inv Counter n m = ()++ {-| Trivial effect annotation is 0 -}+ type Unit Counter = Z+ {-| Compose effects by addition -}+ type Plus Counter n m = n :+ m++ return a = Counter a+ (Counter a) >>= k = Counter . forget $ k a++{-| A 'tick' provides a way to increment the counter -}+tick :: a -> Counter (S Z) a+tick x = Counter x++
+ src/Control/Effect/CounterNat.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE TypeFamilies, TypeOperators, DataKinds #-}++module Control.Effect.CounterNat where++import Control.Effect+import GHC.TypeLits+import Prelude hiding (Monad(..))++{-| Provides a way to 'count' in the type-level with a monadic interface+ to sum up the individual counts of subcomputations. Instead + of using our own inductive natural number typ, this uses the 'Nat' kind from 'GHC.TypeLits' -}++{-| The counter has no semantic meaning -}+data Counter (n :: Nat) a = Counter { forget :: a }++instance Effect Counter where+ type Inv Counter n m = ()+ {-| Trivial effect annotation is 0 -}+ type Unit Counter = 0+ {-| Compose effects by addition -}+ type Plus Counter n m = n + m++ return a = Counter a + (Counter a) >>= k = Counter . forget $ k a++{-| A 'tick' provides a way to increment the counter -}+tick :: a -> Counter 1 a+tick x = Counter x
+ src/Control/Effect/Helpers/List.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeOperators, TypeFamilies, + MultiParamTypeClasses, FlexibleInstances #-}++module Control.Effect.Helpers.List where++data List (l::[*]) where+ Nil :: List '[]+ Cons :: x -> List xs -> List (x ': xs)++type family (:++) (s :: [*]) (t :: [*]) :: [*]+type instance '[] :++ ys = ys+type instance (x ': xs) :++ ys = x ': (xs :++ ys)++append :: List s -> List t -> List (s :++ t)+append Nil xs = xs+append (Cons x xs) ys = Cons x (append xs ys)++class Split s t where+ split :: List (s :++ t) -> (List s, List t)++instance Split '[] xs where+ split xs = (Nil, xs)++instance Split xs ys => Split (x ': xs) ys where+ split (Cons x xs) = let (xs', ys') = split xs+ in (Cons x xs', ys')
+ src/Control/Effect/Maybe.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE EmptyDataDecls, TypeFamilies, GADTs #-}++module Control.Effect.Maybe where++import Prelude hiding (Monad(..))++import Control.Effect+import Control.Effect.Cond++{-| Provides an indexed version of the |Maybe| monad -}++data F +data T +data U++data IMaybe p a where+ INothing :: IMaybe F a + IJust :: a -> IMaybe T a + IDyn :: IMaybe s a -> IMaybe U a -- dynamic partiality++instance Show a => Show (IMaybe p a) where+ show INothing = "Nothing"+ show (IJust a) = "Just " ++ show a+ show (IDyn a) = show a++instance Effect IMaybe where+ type Inv IMaybe s t = ()+ type Unit IMaybe = T++ type Plus IMaybe F s = F -- conjunction+ type Plus IMaybe T s = s+ type Plus IMaybe U s = U++ return x = IJust x++ -- static+ (IJust x) >>= k = k x+ INothing >>= k = INothing++ -- dynamic (statically undecidable)+ (IDyn (IJust a)) >>= k = IDyn (k a)+ (IDyn (INothing)) >>= k = IDyn INothing + +instance Cond IMaybe where+ type AltInv IMaybe s t = ()++ type Alt IMaybe T T = T+ type Alt IMaybe F F = F++ type Alt IMaybe F T = U+ type Alt IMaybe T F = U++ -- statically decidable+ ifM True (IJust x) (IJust y) = IJust x+ ifM False (IJust x) (IJust y) = IJust y+ ifM True INothing INothing = INothing+ ifM False INothing INothing = INothing++ -- dynamic (statically undecidable)+ ifM True INothing (IJust x) = IDyn INothing+ ifM False INothing (IJust x) = IDyn (IJust x)+ ifM True (IJust x) INothing = IDyn (IJust x)+ ifM False (IJust x) INothing = IDyn INothing
+ src/Control/Effect/Monad.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE TypeFamilies, GADTs #-}++module Control.Effect.Monad where++import Control.Effect+import Prelude hiding (Monad(..))+import qualified Prelude as P+++{-| All monads are parametric effect monads with a trivial singleton-monoid index. +This wrapper wraps normal monads into the Effect interface using the 'M' contructor.+-}++{-| Wrap regular monads up -}+data Monad m t a where+ Wrap :: P.Monad m => m a -> Monad m () a++{-| Unwrap a monad -}+unWrap :: P.Monad m => Monad m t a -> m a+unWrap (Wrap m) = m++instance (P.Monad m) => Effect (Monad m) where+ {-| Trivial singleton monoid -}+ type Inv (Monad m) s t = ()+ type Unit (Monad m) = ()+ type Plus (Monad m) s t = ()++ return x = Wrap (P.return x)+ (Wrap x) >>= f = Wrap ((P.>>=) x (unWrap . f))+ ++
+ src/Control/Effect/Parameterised.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE KindSignatures, TypeFamilies, ConstraintKinds, PolyKinds, DataKinds #-}++module Control.Effect.Parameterised where++import Control.Effect++{-| Implements Bob Atkey's 'parametric monads', + and also the Control.Monad.Indexed package, by emulating+ indexing by morphisms -}++{-| Data type of morphisms -}+newtype T (i :: Morph * *) a = T a++{-| Data type denoting either a morphisms with source and target types, or identity -}+data Morph a b = M a b | Id++instance Effect (T :: ((Morph * *) -> * -> *)) where+ type Unit T = Id+ type Plus T (M a b) (M c d) = M a d+ type Plus T Id (M a b) = M a b+ type Plus T (M a b) Id = M a b+ type Inv T (M a b) (M c d) = c ~ d++ return a = T a+ (T x) >>= k = let T y = k x in T y
+ src/Control/Effect/ReadOnceReader.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, DataKinds,+ TypeOperators #-}++module Control.Effect.ReadOnceReader (ask,Reader(..),List(..)) where++import Control.Effect+import Control.Effect.Cond+import Control.Effect.Helpers.List+import Prelude hiding (Monad(..))++{-| Provides a weak reader monad, which can only read an item once. Provides+ an effect system as a list of the items that have been read -}++data Reader (r :: [*]) a = R { runReader :: (List r -> a) }++instance Effect Reader where+ type Inv Reader s t = Split s t++ type Unit Reader = '[]+ type Plus Reader s t = s :++ t++ return x = R $ \Nil -> x+ (R e) >>= k = R $ \xs -> let (s, t) = split xs+ in (runReader $ k (e s)) t++{-| 'ask' for a value of type 'a' -}+ask :: Reader '[a] a+ask = R $ \(Cons a Nil) -> a++instance Cond Reader where+ type AltInv Reader s t = Split s t+ type Alt Reader s t = s :++ t++ ifM True (R x) (R y) = R $ \rs -> let (r, s) = split rs+ _ = y s + in x r+ ifM False (R x) (R y) = R $ \rs -> let (r, s) = split rs+ _ = x r + in y s
+ src/Control/Effect/Reader.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE TypeFamilies, FlexibleInstances, FlexibleContexts, MultiParamTypeClasses, + UndecidableInstances, RebindableSyntax, DataKinds, TypeOperators, PolyKinds, + ConstraintKinds #-}++module Control.Effect.Reader (Reader(..), ask, merge, (:->)(..), Var(..), Subset, Set(..)) where++import Control.Effect+import Data.Type.Set+import Prelude hiding (Monad(..))+import GHC.TypeLits+import GHC.Prim++{-| Provides a effect-parameterised version of the class reader monad. Effects+ are sets of variable-type pairs, providing an effect system for reader effects. -}++data Reader s a = IxR { runReader :: Set s -> a }++instance Effect Reader where+ type Inv Reader f g = (IsSet f, IsSet g, Split f g (Union f g))++ {-| A trivial effect is the empty set -}+ type Unit Reader = '[]+ {-| Effects are combined by set union -}+ type Plus Reader f g = Union f g++ {-| Trivially pure computation has an empty reader environment -}+ return x = IxR $ \Empty -> x+ {-| Composing copmutations splits the reader requirements between the two -}+ (IxR e) >>= k = IxR $ \fg -> let (f, g) = split fg+ in (runReader $ k (e f)) g++{-| 'ask' for a variable 'v' of type 'a', raising an effect -}+ask :: Var v -> Reader '[v :-> a] a+ask Var = IxR $ \(Ext (Var :-> a) Empty) -> a++{-| Provides a way to emulated the ImplicitParams features of GHC/Haskell -}+merge :: (Unionable s t) => (a -> Reader (Union s t) b) -> Reader s (a -> Reader t b)+merge k = IxR $ \s -> \a -> IxR $ \t -> runReader (k a) (union s t)++{-| If 's' is a subset of 't' then, 's' is a subeffect of 't' -}+instance Subset s t => Subeffect Reader s t where+ sub (IxR e) = IxR $ \st -> let s = subset st in e s++{-+{-| Define the operation for removing duplicates using mappend -}+instance (Nubable (e ': s)) => Nubable (e ': e ': s) where+ nub (Ext _ (Ext x xs)) = nub (Ext x xs)+-}
+ src/Control/Effect/State.hs view
@@ -0,0 +1,180 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, + UndecidableInstances, RebindableSyntax, DataKinds, + TypeOperators, PolyKinds, FlexibleContexts, ConstraintKinds, + OverlappingInstances, IncoherentInstances + #-}++module Control.Effect.State (Set(..), get, put, State(..), (:->)(..), (:!)(..),+ Eff(..), Action(..), Var(..), union, UnionS, + Reads(..), Writes(..), Unionable, Sortable, SetLike, + StateSet, + --- may not want to export these+ IntersectR, Update, Sort, Split) where++import Control.Effect+import Data.Type.Set hiding (Unionable, union, SetLike, Nub, Nubable(..))+import qualified Data.Type.Set as Set++import Prelude hiding (Monad(..),reads)+import GHC.TypeLits++{-| Provides an effect-parameterised version of the state monad, which gives an + effect system for stateful computations with annotations that are sets of + variable-type-action triples. -}+++{-| Distinguish reads, writes, and read-writes -}+data Eff = R | W | RW+{-| Provides a wrapper for effect actions -}+data Action (s :: Eff) = Eff++instance Show (Action R) where+ show _ = "R"+instance Show (Action W) where+ show _ = "W"+instance Show (Action RW) where+ show _ = "RW"++{-| Describes an effect action 's' on a value of type 'a' -}+data (:!) (a :: *) (s :: Eff) = a :! (Action s) ++instance (Show (Action f), Show a) => Show (a :! f) where+ show (a :! f) = show a ++ " ! " ++ show f++infixl 3 :!++type SetLike s = Nub (Sort s)+type UnionS s t = Nub (Sort (Append s t))+type Unionable s t = (Sortable (Append s t), Nubable (Sort (Append s t)) (Nub (Sort (Append s t))),+ Split s t (Union s t))++{-| Union operation for state effects -}+union :: (Unionable s t) => Set s -> Set t -> Set (UnionS s t)+union s t = nub (quicksort (append s t))++{-| Type-level remove duplicates from a type-level list and turn different sorts into 'RW'| -}+type family Nub t where+ Nub '[] = '[]+ Nub '[e] = '[e]+ Nub (e ': e ': as) = Nub (e ': as)+ Nub ((k :-> a :! s) ': (k :-> a :! t) ': as) = Nub ((k :-> a :! RW) ': as)+ Nub (e ': f ': as) = e ': Nub (f ': as)++{-| Value-level remove duplicates from a type-level list and turn different sorts into 'RW'| -}+class Nubable t v where+ nub :: Set t -> Set v++instance Nubable '[] '[] where+ nub Empty = Empty++instance Nubable '[e] '[e] where+ nub (Ext e Empty) = (Ext e Empty)++instance Nubable ((k :-> b :! s) ': as) as' => + Nubable ((k :-> a :! s) ': (k :-> b :! s) ': as) as' where+ nub (Ext _ (Ext x xs)) = nub (Ext x xs)++instance Nubable ((k :-> a :! RW) ': as) as' => + Nubable ((k :-> a :! s) ': (k :-> a :! t) ': as) as' where+ nub (Ext _ (Ext (k :-> (a :! _)) xs)) = nub (Ext (k :-> (a :! (Eff::(Action RW)))) xs)++instance Nubable ((j :-> b :! t) ': as) as' => + Nubable ((k :-> a :! s) ': (j :-> b :! t) ': as) ((k :-> a :! s) ': as') where+ nub (Ext (k :-> (a :! s)) (Ext (j :-> (b :! t)) xs)) = Ext (k :-> (a :! s)) (nub (Ext (j :-> (b :! t)) xs))+++{-| Update reads, that is any writes are pushed into reads, a bit like intersection -}+class Update s t where+ update :: Set s -> Set t++instance Update xs '[] where+ update _ = Empty++instance Update '[e] '[e] where + update s = s++{-+instance Update ((v :-> b :! R) ': as) as' => Update ((v :-> a :! s) ': (v :-> b :! s) ': as) as' where+ update (Ext _ (Ext (v :-> (b :! _)) xs)) = update (Ext (v :-> (b :! (Eff::(Action R)))) xs) -}++instance Update ((v :-> a :! R) ': as) as' => Update ((v :-> a :! W) ': (v :-> b :! R) ': as) as' where+ update (Ext (v :-> (a :! _)) (Ext _ xs)) = update (Ext (v :-> (a :! (Eff::(Action R)))) xs)++instance Update ((u :-> b :! s) ': as) as' => Update ((v :-> a :! W) ': (u :-> b :! s) ': as) as' where+ update (Ext _ (Ext e xs)) = update (Ext e xs)++instance Update ((u :-> b :! s) ': as) as' => Update ((v :-> a :! R) ': (u :-> b :! s) ': as) ((v :-> a :! R) ': as') where+ update (Ext e (Ext e' xs)) = Ext e $ update (Ext e' xs)++type IntersectR s t = (Sortable (Append s t), Update (Sort (Append s t)) t)++{-| Intersects a set of write effects and a set of read effects, updating any read effects with+ any corresponding write value -}+intersectR :: (Reads t ~ t, Writes s ~ s, IsSet s, IsSet t, IntersectR s t) => Set s -> Set t -> Set t+intersectR s t = update (quicksort (append s t))++{-| Parametric effect state monad -}+data State s a = State { runState :: Set (Reads s) -> (a, Set (Writes s)) }++{-| Calculate just the reader effects -}+type family Reads t where+ Reads '[] = '[]+ Reads ((k :-> a :! R) ': xs) = (k :-> a :! R) ': (Reads xs)+ Reads ((k :-> a :! RW) ': xs) = (k :-> a :! R) ': (Reads xs)+ Reads ((k :-> a :! W) ': xs) = Reads xs++{-| Calculate just the writer effects -}+type family Writes t where+ Writes '[] = '[]+ Writes ((k :-> a :! W) ': xs) = (k :-> a :! W) ': (Writes xs)+ Writes ((k :-> a :! RW) ': xs) = (k :-> a :! W) ': (Writes xs)+ Writes ((k :-> a :! R) ': xs) = Writes xs++{-| Read from a variable 'v' of type 'a'. Raise a read effect. -}+get :: Var v -> State '[v :-> a :! R] a+get _ = State $ \(Ext (v :-> (a :! _)) Empty) -> (a, Empty)++{-| Write to a variable 'v' with a value of type 'a'. Raises a write effect -}+put :: Var v -> a -> State '[k :-> a :! W] ()+put _ a = State $ \Empty -> ((), Ext (Var :-> a :! Eff) Empty)++{-| Captures what it means to be a set of state effects -}+type StateSet f = (StateSetProperties f, StateSetProperties (Reads f), StateSetProperties (Writes f))+type StateSetProperties f = (IntersectR f '[], IntersectR '[] f,+ UnionS f '[] ~ f, Split f '[] f, + UnionS '[] f ~ f, Split '[] f f, + UnionS f f ~ f, Split f f f,+ Unionable f '[], Unionable '[] f)+ +-- Indexed monad instance+instance Effect State where+ type Inv State s t = (IsSet s, IsSet (Reads s), IsSet (Writes s),+ IsSet t, IsSet (Reads t), IsSet (Writes t),+ Reads (Reads t) ~ Reads t, Writes (Writes s) ~ Writes s, + Split (Reads s) (Reads t) (Reads (UnionS s t)), + Unionable (Writes s) (Writes t), + IntersectR (Writes s) (Reads t), + Writes (UnionS s t) ~ UnionS (Writes s) (Writes t))++ {-| Pure state effect is the empty state -}+ type Unit State = '[]+ {-| Combine state effects via specialised union (which combines R and W effects on the same+ variable into RW effects -}+ type Plus State s t = UnionS s t++ return x = State $ \Empty -> (x, Empty)++ (State e) >>= k = + State $ \st -> let (sR, tR) = split st+ (a, sW) = e sR+ (b, tW) = (runState $ k a) (sW `intersectR` tR)+ in (b, sW `union` tW) +++{-+instance (Split s t (Union s t), Sub s t) => Subeffect State s t where+ sub (State e) = IxR $ \st -> let (s, t) = split st + _ = ReflP p t + in e s+-}+
+ src/Control/Effect/Update.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, RebindableSyntax, + GADTs, EmptyDataDecls, DataKinds #-}++module Control.Effect.Update where ++import Control.Effect+import Prelude hiding (Monad(..))++{-| Parametric effect update monad. A bit like a writer monad specialised to the 'Maybe' monoid, + providing a single memory cell that can be updated, but with heterogeneous behaviour. + Provides an effect system that explains whether a single memory cell has been updated or not -}++data Eff (w :: Maybe *) where+ Put :: a -> Eff (Just a)+ NoPut :: Eff Nothing++data Update w a = Update { runUpdate :: (a, Eff w) }++-- Uupdate monad+instance Effect Update where + type Inv Update s t = ()+ type Unit Update = Nothing+ type Plus Update s Nothing = s+ type Plus Update s (Just t) = Just t++ return x = Update (x, NoPut)+ (Update (a, w)) >>= k =+ Update $ update w (runUpdate $ k a)+ where + update :: Eff s -> (b, Eff t) -> (b, Eff (Plus Update s t))+ update w (b, NoPut) = (b, w)+ update _ (b, Put w'') = (b, Put w'')++{-| Update the memory cell with a new value of type 'a' -}+put :: a -> Update (Just a) ()+put x = Update ((), Put x)
+ src/Control/Effect/Vector.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE GADTs, TypeFamilies, EmptyDataDecls, UndecidableInstances, MultiParamTypeClasses, TypeSynonymInstances, FlexibleContexts #-}++module Control.Effect.Vector where++import Prelude hiding (Monad(..))+import Control.Effect++-- Sized-vector type++data Z+data S n ++data Vector n a where+ Nil :: Vector Z a+ Cons ::a -> Vector n a -> Vector (S n) a++-- Append function which adds indices++type family Add s t+type instance Add Z m = m+type instance Add (S n) m = S (Add n m)++append :: Vector n a -> Vector m a -> Vector (Add n m) a+append Nil ys = ys+append (Cons x xs) ys = Cons x (append xs ys)++instance Effect Vector where+ -- Effect monoid is (N, *, 1)+ type Inv Vector s t = ()++ type Unit Vector = S Z++ -- Multiplies indicies+ type Plus Vector Z m = Z+ type Plus Vector (S n) m = Add m (Plus Vector n m)++ return x = Cons x Nil+ Nil >>= f = Nil+ (Cons x xs) >>= f = append (f x) (xs >>= f)+++
+ src/Control/Effect/WriteOnceWriter.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleInstances, + TypeOperators, DataKinds, KindSignatures #-}++module Control.Effect.WriteOnceWriter (put, WriteOnce(..)) where++import Control.Effect+import Control.Effect.Helpers.List+import Prelude hiding (Monad(..))++{-| Provides a kind of writer monad, which can only write an item once + (no accumulation), an effect system as a list of the items that have been written -}++data WriteOnce (w :: [*]) a = W { runWriteOnce :: (a, List w) }++instance Effect WriteOnce where+ type Inv WriteOnce s t = ()++ {-| Pure effect is the empty list -}+ type Unit WriteOnce = '[]++ {-| Combine effects by appending effect information -}+ type Plus WriteOnce s t = s :++ t++ return x = W (x, Nil)+ (W (a, r)) >>= k = let (W (b, s)) = k a in W (b, r `append` s)++{-| Write a value of type 'a' -}+put :: a -> WriteOnce '[a] ()+put x = W ((), Cons x Nil)+++
+ src/Control/Effect/Writer.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE GADTs, DataKinds, KindSignatures, TypeOperators, TypeFamilies, + MultiParamTypeClasses, FlexibleInstances, UndecidableInstances, + ScopedTypeVariables, PolyKinds, FlexibleContexts #-}++module Control.Effect.Writer(Writer(..), Symbol, put, (:->), IsSet, Set(..), union, Var(..), + Union, Unionable) where++import Control.Effect +import Data.Type.Set+import Data.Monoid+import GHC.TypeLits+import Prelude hiding (Monad(..))++{-| Provides an effect-parameterised version of the writer monad. Effects+ are sets of variable-type pairs, providing an effect system for writer effects. -}++data Writer w a = Writer { runWriter :: (a, Set w) }++instance Effect Writer where+ type Inv Writer s t = (IsSet s, IsSet t, Unionable s t)++ {-| A trivial effect is the empty set -}+ type Unit Writer = '[]+ {-| Effects are combined by set union -}+ type Plus Writer s t = Union s t++ {-| Trivially pure computation produces an empty state -}+ return x = Writer (x, Empty)+ {-| Composing copmutations takes the union of the writer states, using the monoid + operation to combine writes to the same variable -}+ (Writer (a, w)) >>= k = let Writer (b, w') = k a+ in Writer (b, w `union` w')++{-| Write to variable 'v' with value of type 'a' -}+put :: Var v -> a -> Writer '[v :-> a] ()+put v a = Writer ((), Ext (v :-> a) Empty)++{-| Define the operation for removing duplicates using mappend -}+instance (Monoid u, Nubable ((k :-> u) ': s)) => Nubable ((k :-> u) ': (k :-> u) ': s) where+ nub (Ext (_ :-> u) (Ext (k :-> v) s)) = nub (Ext (k :-> (u `mappend` v)) s)++{- Sub effecting for the parametric effect monad -}+instance Superset s t => Subeffect Writer s t where+ sub (Writer (a, w)) = Writer (a, (superset w)::(Set t))++{-| Computes supersets of sets of variable-type mappings, using the 'mempty' operation -}+class Superset s t where+ superset :: Set s -> Set t++instance Superset '[] '[] where+ superset Empty = Empty++instance (Monoid x, Superset '[] s) => Superset '[] ((k :-> x) ': s) where+ superset Empty = Ext (Var :-> mempty) (superset Empty)++instance Superset s t => Superset ((k :-> v) ': s) ((k :-> v) ': t) where+ superset (Ext x xs) = Ext x (superset xs)