packages feed

effects 0.2.1 → 0.2.2

raw patch · 23 files changed

+522/−543 lines, 23 filesdep ~containerssetup-changed

Dependency ranges changed: containers

Files

− ._LICENSE

binary file changed (185 → absent bytes)

− ._README.md

binary file changed (187 → absent bytes)

− ._effects.cabal

binary file changed (186 → absent bytes)

− ._examples.hs

binary file changed (187 → absent bytes)

LICENSE view
@@ -1,31 +1,31 @@-Copyright Sjoerd Visscher 2011--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.--    * Neither the name of Sjoerd Visscher nor the names of other-      contributors may be used to endorse or promote products derived-      from this software without specific prior written permission.--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.-+Copyright Sjoerd Visscher 2011
+
+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.
+
+    * Neither the name of Sjoerd Visscher nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+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.
+
− README.md
@@ -1,28 +0,0 @@-Control.Effects-===============--Control.Effects is a Haskell library for programming with effects, like in the the [Eff language][Eff] by Andrej Bauer and Matija Pretnar. Effects can be used instead of monad transformers, they are designed to be easier to use and to define.--Installation---------------    cabal install effects--Using effects----------------Here's an example how to use the state effect from `Control.Effects.State`.--    example :: (Int, Int)-    example = run $ do-      with (ref 5) $ \x -> do-        with (ref 10) $ \y -> do-          x =: (+) <$> get x <*> get y-          y =: (+) <$> get x <*> get y-          (,) <$> get x <*> get y--Every instance of an effect is given a name (`x` and `y` in this example), which makes is possible to easily mix several instances of the same effect.--For more examples see [examples.hs](https://github.com/sjoerdvisscher/effects/blob/master/examples.hs).--[Eff]: http://math.andrej.com/category/programming/eff/?category_name=programming/eff
Setup.lhs view
@@ -1,3 +1,3 @@-#!/usr/bin/env runhaskell-> import Distribution.Simple+#!/usr/bin/env runhaskell
+> import Distribution.Simple
 > main = defaultMain
effects.cabal view
@@ -1,39 +1,42 @@-name:                effects-version:             0.2.1-synopsis:            Computational Effects--description:         Control.Effects is a library for programming with effects, like in the the Eff language by -                     Andrej Bauer and Matija Pretnar. Effects can be used instead of monad transformers.-                     .-                     See the home page for some example code.--category:            Control, Monads-license:             BSD3-license-file:        LICENSE-author:              Sjoerd Visscher-maintainer:          sjoerd@w3future.com-stability:           experimental-homepage:            http://github.com/sjoerdvisscher/effects-bug-reports:         http://github.com/sjoerdvisscher/effects/issues--build-type:          Simple-cabal-version:       >= 1.6--Library-  HS-Source-Dirs:      src-  build-depends:       base >= 3 && < 5, -                       containers  >= 0.4 && < 0.5,-                       newtype >= 0.2 && < 0.3,-                       void-  exposed-modules:     -    Control.Effects-    Control.Effects.Cont-    Control.Effects.Either-    Control.Effects.Error-    Control.Effects.NonDet-    Control.Effects.State-    Control.Effects.Writer-    -source-repository head-  type:     git+name:                effects
+version:             0.2.2
+synopsis:            Computational Effects
+
+description:         Control.Effects is a library for programming with effects, like in the the Eff language by 
+                     Andrej Bauer and Matija Pretnar. Effects can be used instead of monad transformers.
+                     .
+                     See the home page for some example code.
+
+category:            Control, Monads
+license:             BSD3
+license-file:        LICENSE
+author:              Sjoerd Visscher
+maintainer:          sjoerd@w3future.com
+stability:           experimental
+homepage:            http://github.com/sjoerdvisscher/effects
+bug-reports:         http://github.com/sjoerdvisscher/effects/issues
+
+build-type:          Simple
+cabal-version:       >= 1.6
+
+Extra-Source-Files:
+  examples.hs
+
+Library
+  HS-Source-Dirs:      src
+  build-depends:       base >= 3 && < 5, 
+                       containers  >= 0.4 && < 0.6,
+                       newtype >= 0.2 && < 0.3,
+                       void
+  exposed-modules:     
+    Control.Effects
+    Control.Effects.Cont
+    Control.Effects.Either
+    Control.Effects.Error
+    Control.Effects.NonDet
+    Control.Effects.State
+    Control.Effects.Writer
+    
+source-repository head
+  type:     git
   location: git://github.com/sjoerdvisscher/effects.git
examples.hs view
@@ -1,109 +1,110 @@-module Main where--import Control.Effects-import Control.Effects.Cont-import Control.Effects.Either-import Control.Effects.Error-import Control.Effects.State-import Control.Effects.Writer-import Control.Effects.NonDet--import qualified Data.Set as Set-import Data.Monoid-import Control.Applicative---testIO :: IO ()-testIO = runBase $ do-  base $ putStrLn "What's your name?"-  name <- base getLine-  base $ putStrLn $ "Hello, " ++ name--testRefIO :: IO ()-testRefIO = runBase $ do-  with (ref 5) $ \x -> do-    val <- get x-    base $ print val--testRef :: (Int, Int)-testRef = run $ do-  with (ref 5) $ \x -> do-    with (ref 10) $ \y -> do-      x =: (+) <$> get x <*> get y-      y =: (+) <$> get x <*> get y-      (,) <$> get x <*> get y-      --testWriter :: (String, (String, Int))-testWriter = run $ do-  with writer $ \w1 -> do-    with writer $ \w2 -> do-      tell w1 "123"-      tell w2 "abc"-      tell w1 "456"-      tell w2 "def"-      return 1---testSet :: Set.Set Int-testSet = run $-  with set $ \s -> do-    x <- choose s [1, 2]-    y <- choose s [1, 2]-    z <- choose s [1, 2]-    return $ x * x - y * z * x + z * z * z - y * y * x--testAccumulate :: Bool-testAccumulate = run $-  with (accumulate Any) $ \s -> do-    x <- choose s [1, 2]-    y <- choose s [1, 2]-    z <- choose s [1, 2]-    return $ x * x - y * z * x + z * z * z - y * y * x == 0---testDfs :: [Int] -> [(Int, Int, Int)]-testDfs = run . with (dfs return) . triples--testBfs :: [Int] -> [(Int, Int, Int)]-testBfs = run . with (bfs return) . triples--triples :: (Num a, Monoid e, AutoLift e m n) => [a] -> Effect e m -> n (a, a, a)-triples range s = do-  x <- choose s range-  y <- choose s range-  z <- choose s range-  if x*x + y*y == z*z then return (x,y,z) else choose s []---testError :: IO ()-testError = runBase $ do-  with (catchError (\e -> base $ putStrLn ("Error: " ++ e))) $ \c -> do-    base $ putStrLn "before"-    throwError c "123"-    base $ putStrLn "after"-  --testEither :: IO ()-testEither = runBase $ do-  with (catchEither (\e -> base $ putStrLn ("Error: " ++ e))) $ \c -> do-    base $ putStrLn "before"-    throwEither c "123"-    base $ putStrLn "after"---testReset1 :: Int-testReset1 = run $ do-  with reset $ \r -> do-    x <- shift r (\k -> k (k (k (return 7))))-    return $ x * 2 + 1--testReset2 :: IO ()-testReset2 = runBase $ do-  r <- with reset $ \promptA -> do-    base $ putStrLn "Batman"-    with reset $ \promptB -> do-      shift promptB $ \k -> k (k (shift promptA $ \l -> l (l (return ()))))-      base $ putStrLn "Robin"-    base $ putStrLn "Cat woman"-  base $ print r+module Main where
+
+import Control.Effects
+import Control.Effects.Cont
+import Control.Effects.Either
+import Control.Effects.Error
+import Control.Effects.State
+import Control.Effects.Writer
+import Control.Effects.NonDet
+
+import qualified Data.Set as Set
+import Data.Monoid
+import Control.Applicative
+
+
+testIO :: IO ()
+testIO = runBase $ do
+  base $ putStrLn "What's your name?"
+  name <- base getLine
+  base $ putStrLn $ "Hello, " ++ name
+
+testRefIO :: IO ()
+testRefIO = runBase $ do
+  with (ref 5) $ \x -> do
+    val <- get x
+    base $ print val
+
+testRef :: (Int, Int)
+testRef = run $ do
+  with (ref 5) $ \x -> do
+    with (ref 10) $ \y -> do
+      x =: (+) <$> get x <*> get y
+      y =: (+) <$> get x <*> get y
+      (,) <$> get x <*> get y
+      
+
+testWriter :: (String, (String, Int))
+testWriter = run $ do
+  with writer $ \w1 -> do
+    with writer $ \w2 -> do
+      tell w1 "123"
+      tell w2 "abc"
+      tell w1 "456"
+      tell w2 "def"
+      return 1
+
+
+testSet :: Set.Set Int
+testSet = run $
+  with set $ \s -> do
+    x <- choose s [1, 2]
+    y <- choose s [1, 2]
+    z <- choose s [1, 2]
+    return $ x * x - y * z * x + z * z * z - y * y * x
+
+testAccumulate :: Bool
+testAccumulate = run $
+  with (accumulate Any) $ \s -> do
+    x <- choose s [1, 2]
+    y <- choose s [1, 2]
+    z <- choose s [1, 2]
+    return $ x * x - y * z * x + z * z * z - y * y * x == 0
+
+
+testDfs :: [Int] -> [(Int, Int, Int)]
+testDfs = run . with (dfs return) . triples
+
+testBfs :: [Int] -> [(Int, Int, Int)]
+testBfs = run . with (bfs return) . triples
+
+triples :: (Num a, Monoid e, AutoLift e m n) => [a] -> Effect e m -> n (a, a, a)
+triples range s = do
+  x <- choose s range
+  y <- choose s range
+  z <- choose s range
+  guard s $ x*x + y*y == z*z
+  return (x,y,z)
+
+
+testError :: IO ()
+testError = runBase $ do
+  with (catchError (\e -> base $ putStrLn ("Error: " ++ e))) $ \c -> do
+    base $ putStrLn "before"
+    throwError c "123"
+    base $ putStrLn "after"
+  
+
+testEither :: IO ()
+testEither = runBase $ do
+  with (catchEither (\e -> base $ putStrLn ("Error: " ++ e))) $ \c -> do
+    base $ putStrLn "before"
+    throwEither c "123"
+    base $ putStrLn "after"
+
+
+testReset1 :: Int
+testReset1 = run $ do
+  with reset $ \r -> do
+    x <- shift r (\k -> k (k (k (return 7))))
+    return $ x * 2 + 1
+
+testReset2 :: IO ()
+testReset2 = runBase $ do
+  r <- with reset $ \promptA -> do
+    base $ putStrLn "Batman"
+    with reset $ \promptB -> do
+      shift promptB $ \k -> k (k (shift promptA $ \l -> l (l (return ()))))
+      base $ putStrLn "Robin"
+    base $ putStrLn "Cat woman"
+  base $ print r
− src/Control/._Effects.hs

binary file changed (187 → absent bytes)

src/Control/Effects.hs view
@@ -1,194 +1,194 @@-{-# LANGUAGE MultiParamTypeClasses, KindSignatures, ScopedTypeVariables, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}-module Control.Effects (--  -- * Running effects-  -- $rundoc-    with-  , run-  -- * Defining effects  -  -- $defdoc-  , Handler(..)-  , operation-  -- * Base monad-  -- $basedoc-  , runBase-  , base-  -- * Effects machinery-  -- $macdoc-  , Layer(..)-  , Base(..)-  , Pure(..)-  , Effect-  , AutoLift-  , AutoLiftBase--) where--import Control.Applicative-import Control.Monad-import Data.Monoid---- $rundoc--- Here's an example how to use the state effect from 'Control.Effects.State':------ > example :: Int--- > example = run $ do--- >   with (ref 10) $ \u -> do--- >     val <- get u--- >     put u (val + 5)--- >     get u---- | @with@ takes a handler and creates a new effect instance.---   The @Effect@ is passed on to a function which can use it to do operations with it.-with :: Monad m => Handler e r m a -> (Effect e m -> Layer e m a) -> m r-with h f = runLayer (f Effect) (ret h) >>= fin h---- | Unwrap the result of the top-level effect.-run :: Base Pure a -> a-run (Base (Pure a)) = a----- $defdoc--- Here's and example how to define the state effect from 'Control.Effects.Writer':------ > writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a--- > writer = Handler--- >   { ret = \a -> return (mempty, a)--- >   , fin = return--- >   }--- > --- > tell :: (AutoLift (w, r) m n, Monoid w) => Effect (w, r) m -> w -> n ()--- > tell p v = operation p $ \k -> do--- >   (w, r) <- k ()--- >   return (mappend v w, r)---- | A @Handler e r m a@ is a handler of effects with type @e@. ---   The @ret@ field provides a function to lift pure values into the effect.---   The @fin@ field provides a function to extract a final value of type @r@ from the effect.---   The parameter @m@ should normally be left polymorphic, it's the monad that handles the other effects.-data Handler e r m a = Handler-  { ret :: a -> m e-  , fin :: e -> m r-  }---- | @operation@ takes an effect identifier generated by `with` and a function which takes a continuation as parameter.---   The result is auto-lifted so it can be used inside any other effect.-operation :: AutoLift e m n => Effect e m -> ((a -> m e) -> m e) -> n a-operation = operation'----- $basedoc--- The effects are layered on top of a base monad. Here's an example how to use `IO` as a base monad:--- --- > exampleIO :: IO ()--- > exampleIO = runBase $ do--- >   with (ref 5) $ \x -> do--- >     val <- get x--- >     base $ print val---- | @base@ takes a computation in the base monad and auto-lifts it so it can be used inside any effect.-base :: AutoLiftBase m n => m a -> n a-base = base'---- | Unwrap the result of a computation using a base monad.-runBase :: Base m a -> m a-runBase (Base m) = m----- $macdoc--- Effects are layered in a stack on top of a base monad. Just like with monad transformers, operations lower in the stack--- need to be lifted to be able to be used together with operations higher in the stack. But as there are only two  monads--- in play, `Layer` and `Base`, and because each operation is identified with exactly one layer using the `Effect` type,--- lifting can be done automatically.------ The following types and classes show up in the type signatures. The compiler should be able to infer them for you.---- | @Layer e m@ is a monad that adds an effect @e@ to the underlying monad @m@.---   (It is the continuation monad transformer with a friendlier name.)-newtype Layer e m a = Layer { runLayer :: (a -> m e) -> m e }--instance Functor (Layer e m) where-  fmap f m = Layer $ \k -> runLayer m (k . f)--instance Applicative (Layer e m) where-  pure a   = Layer $ \k -> k a-  m <*> v  = Layer $ \k -> runLayer m (\f -> runLayer v (k . f))--instance (Monoid e, Applicative m) => Alternative (Layer e m) where-  empty = Layer $ \_ -> pure mempty-  l <|> r = Layer $ \k -> mappend <$> runLayer l k <*> runLayer r k--instance Monad (Layer e m) where-  return a = Layer $ \k -> k a-  m >>= f  = Layer $ \k -> runLayer m (\a -> runLayer (f a) k)--instance (Monoid e, Applicative m) => MonadPlus (Layer e m) where-  mzero = empty-  mplus = (<|>)----- | @Pure@ is the identity monad and is used when no other base monad is needed.-newtype Pure a = Pure a--instance Functor Pure where-  fmap f (Pure a) = Pure (f a)--instance Applicative Pure where-  pure = Pure-  Pure f <*> Pure a = Pure (f a)  -  -instance Monad Pure where-  return = Pure-  Pure a >>= f = f a----- | @Base m@ is a newtype wrapper around a monadic computation.-newtype Base m a = Base (m a)--instance Functor m => Functor (Base m) where-  fmap f (Base m) = Base (fmap f m)--instance Applicative m => Applicative (Base m) where-  pure = Base . pure-  Base m <*> Base v = Base (m <*> v)-  -instance Monad m => Monad (Base m) where-  return = Base . return-  Base m >>= f = Base $ m >>= runBase . f---- | @Effect e m@ is a proxy for the type checker to be able to work with multiple effects at the same time.-data Effect e (m :: * -> *) = Effect---class (Monad m, Monad n) => AutoLift e m n where-  operation' :: Effect e m -> ((a -> m e) -> m e) -> n a--instance (Monad m, Monad n, AutoLiftInternal (Layer e m) (Base    n) (Layer e m) (Base    n)) => AutoLift e m (Base    n) where-  operation' _ f = autolift (Proxy :: Proxy (Layer e m)) (Proxy :: Proxy (Base    n)) (Layer f)-instance (Monad m, Monad n, AutoLiftInternal (Layer e m) (Layer d n) (Layer e m) (Layer d n)) => AutoLift e m (Layer d n) where-  operation' _ f = autolift (Proxy :: Proxy (Layer e m)) (Proxy :: Proxy (Layer d n)) (Layer f)---class (Monad m, Monad n) => AutoLiftBase m n where-  base' :: m a -> n a--instance (Monad m, Monad n, AutoLiftInternal (Base    m) (Base    n) (Base    m) (Base    n)) => AutoLiftBase m (Base    n) where-  base' m        = autolift (Proxy :: Proxy (Base    m)) (Proxy :: Proxy (Base    n)) (Base m)-instance (Monad m, Monad n, AutoLiftInternal (Base    m) (Layer e n) (Base    m) (Layer e n)) => AutoLiftBase m (Layer e n) where-  base' m        = autolift (Proxy :: Proxy (Base    m)) (Proxy :: Proxy (Layer e n)) (Base m)---data Proxy (m :: * -> *) = Proxy--class (Monad m1, Monad m2) =>  AutoLiftInternal m1 m2 n1 n2 where-  autolift :: Proxy n1 -> Proxy n2 -> m1 a -> m2 a--pre :: Proxy (Layer r m) -> Proxy m-pre Proxy = Proxy--instance (Monad m)                             => AutoLiftInternal m           m   (Base    n)  (Base    n)  where-  autolift Proxy Proxy = id-instance (AutoLiftInternal m1 m2 (Base n1) n2) => AutoLiftInternal m1 (Layer r m2) (Base    n1) (Layer s n2) where-  autolift p1 p2 = Layer . (>>=) . autolift p1 (pre p2)-instance (AutoLiftInternal m1 m2       n1  n2) => AutoLiftInternal m1          m2  (Layer r n1) (Layer s n2) where-  autolift p1 p2 = autolift (pre p1) (pre p2)+{-# LANGUAGE MultiParamTypeClasses, KindSignatures, ScopedTypeVariables, FlexibleInstances, FlexibleContexts, UndecidableInstances #-}
+module Control.Effects (
+
+  -- * Running effects
+  -- $rundoc
+    with
+  , run
+  -- * Defining effects  
+  -- $defdoc
+  , Handler(..)
+  , operation
+  -- * Base monad
+  -- $basedoc
+  , runBase
+  , base
+  -- * Effects machinery
+  -- $macdoc
+  , Layer(..)
+  , Base(..)
+  , Pure(..)
+  , Effect
+  , AutoLift
+  , AutoLiftBase
+
+) where
+
+import Control.Applicative
+import Control.Monad
+import Data.Monoid
+
+-- $rundoc
+-- Here's an example how to use the state effect from 'Control.Effects.State':
+--
+-- > example :: Int
+-- > example = run $ do
+-- >   with (ref 10) $ \u -> do
+-- >     val <- get u
+-- >     put u (val + 5)
+-- >     get u
+
+-- | @with@ takes a handler and creates a new effect instance.
+--   The @Effect@ is passed on to a function which can use it to do operations with it.
+with :: Monad m => Handler e r m a -> (Effect e m -> Layer e m a) -> m r
+with h f = runLayer (f Effect) (ret h) >>= fin h
+
+-- | Unwrap the result of the top-level effect.
+run :: Base Pure a -> a
+run (Base (Pure a)) = a
+
+
+-- $defdoc
+-- Here's and example how to define the state effect from 'Control.Effects.Writer':
+--
+-- > writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a
+-- > writer = Handler
+-- >   { ret = \a -> return (mempty, a)
+-- >   , fin = return
+-- >   }
+-- > 
+-- > tell :: (AutoLift (w, r) m n, Monoid w) => Effect (w, r) m -> w -> n ()
+-- > tell p v = operation p $ \k -> do
+-- >   (w, r) <- k ()
+-- >   return (mappend v w, r)
+
+-- | A @Handler e r m a@ is a handler of effects with type @e@. 
+--   The @ret@ field provides a function to lift pure values into the effect.
+--   The @fin@ field provides a function to extract a final value of type @r@ from the effect.
+--   The parameter @m@ should normally be left polymorphic, it's the monad that handles the other effects.
+data Handler e r m a = Handler
+  { ret :: a -> m e
+  , fin :: e -> m r
+  }
+
+-- | @operation@ takes an effect identifier generated by `with` and a function which takes a continuation as parameter.
+--   The result is auto-lifted so it can be used inside any other effect.
+operation :: AutoLift e m n => Effect e m -> ((a -> m e) -> m e) -> n a
+operation = operation'
+
+
+-- $basedoc
+-- The effects are layered on top of a base monad. Here's an example how to use `IO` as a base monad:
+-- 
+-- > exampleIO :: IO ()
+-- > exampleIO = runBase $ do
+-- >   with (ref 5) $ \x -> do
+-- >     val <- get x
+-- >     base $ print val
+
+-- | @base@ takes a computation in the base monad and auto-lifts it so it can be used inside any effect.
+base :: AutoLiftBase m n => m a -> n a
+base = base'
+
+-- | Unwrap the result of a computation using a base monad.
+runBase :: Base m a -> m a
+runBase (Base m) = m
+
+
+-- $macdoc
+-- Effects are layered in a stack on top of a base monad. Just like with monad transformers, operations lower in the stack
+-- need to be lifted to be able to be used together with operations higher in the stack. But as there are only two  monads
+-- in play, `Layer` and `Base`, and because each operation is identified with exactly one layer using the `Effect` type,
+-- lifting can be done automatically.
+--
+-- The following types and classes show up in the type signatures. The compiler should be able to infer them for you.
+
+-- | @Layer e m@ is a monad that adds an effect @e@ to the underlying monad @m@.
+--   (It is the continuation monad transformer with a friendlier name.)
+newtype Layer e m a = Layer { runLayer :: (a -> m e) -> m e }
+
+instance Functor (Layer e m) where
+  fmap f m = Layer $ \k -> runLayer m (k . f)
+
+instance Applicative (Layer e m) where
+  pure a   = Layer $ \k -> k a
+  m <*> v  = Layer $ \k -> runLayer m (\f -> runLayer v (k . f))
+
+instance (Monoid e, Applicative m) => Alternative (Layer e m) where
+  empty = Layer $ \_ -> pure mempty
+  l <|> r = Layer $ \k -> mappend <$> runLayer l k <*> runLayer r k
+
+instance Monad (Layer e m) where
+  return a = Layer $ \k -> k a
+  m >>= f  = Layer $ \k -> runLayer m (\a -> runLayer (f a) k)
+
+instance (Monoid e, Applicative m) => MonadPlus (Layer e m) where
+  mzero = empty
+  mplus = (<|>)
+
+
+-- | @Pure@ is the identity monad and is used when no other base monad is needed.
+newtype Pure a = Pure a
+
+instance Functor Pure where
+  fmap f (Pure a) = Pure (f a)
+
+instance Applicative Pure where
+  pure = Pure
+  Pure f <*> Pure a = Pure (f a)  
+  
+instance Monad Pure where
+  return = Pure
+  Pure a >>= f = f a
+
+
+-- | @Base m@ is a newtype wrapper around a monadic computation.
+newtype Base m a = Base (m a)
+
+instance Functor m => Functor (Base m) where
+  fmap f (Base m) = Base (fmap f m)
+
+instance Applicative m => Applicative (Base m) where
+  pure = Base . pure
+  Base m <*> Base v = Base (m <*> v)
+  
+instance Monad m => Monad (Base m) where
+  return = Base . return
+  Base m >>= f = Base $ m >>= runBase . f
+
+-- | @Effect e m@ is a proxy for the type checker to be able to work with multiple effects at the same time.
+data Effect e (m :: * -> *) = Effect
+
+
+class (Applicative m, Applicative n, Monad m, Monad n) => AutoLift e m n where
+  operation' :: Effect e m -> ((a -> m e) -> m e) -> n a
+
+instance (Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Layer e m) (Base    n) (Layer e m) (Base    n)) => AutoLift e m (Base    n) where
+  operation' _ f = autolift (Proxy :: Proxy (Layer e m)) (Proxy :: Proxy (Base    n)) (Layer f)
+instance (Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Layer e m) (Layer d n) (Layer e m) (Layer d n)) => AutoLift e m (Layer d n) where
+  operation' _ f = autolift (Proxy :: Proxy (Layer e m)) (Proxy :: Proxy (Layer d n)) (Layer f)
+
+
+class (Applicative m, Applicative n, Monad m, Monad n) => AutoLiftBase m n where
+  base' :: m a -> n a
+
+instance (Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Base    m) (Base    n) (Base    m) (Base    n)) => AutoLiftBase m (Base    n) where
+  base' m        = autolift (Proxy :: Proxy (Base    m)) (Proxy :: Proxy (Base    n)) (Base m)
+instance (Applicative m, Applicative n, Monad m, Monad n, AutoLiftInternal (Base    m) (Layer e n) (Base    m) (Layer e n)) => AutoLiftBase m (Layer e n) where
+  base' m        = autolift (Proxy :: Proxy (Base    m)) (Proxy :: Proxy (Layer e n)) (Base m)
+
+
+data Proxy (m :: * -> *) = Proxy
+
+class (Applicative m1, Applicative m2, Monad m1, Monad m2) =>  AutoLiftInternal m1 m2 n1 n2 where
+  autolift :: Proxy n1 -> Proxy n2 -> m1 a -> m2 a
+
+pre :: Proxy (Layer r m) -> Proxy m
+pre Proxy = Proxy
+
+instance (Applicative m, Monad m)              => AutoLiftInternal m           m   (Base    n)  (Base    n)  where
+  autolift Proxy Proxy = id
+instance (AutoLiftInternal m1 m2 (Base n1) n2) => AutoLiftInternal m1 (Layer r m2) (Base    n1) (Layer s n2) where
+  autolift p1 p2 = Layer . (>>=) . autolift p1 (pre p2)
+instance (AutoLiftInternal m1 m2       n1  n2) => AutoLiftInternal m1          m2  (Layer r n1) (Layer s n2) where
+  autolift p1 p2 = autolift (pre p1) (pre p2)
− src/Control/Effects/._Cont.hs

binary file changed (186 → absent bytes)

− src/Control/Effects/._Either.hs

binary file changed (186 → absent bytes)

− src/Control/Effects/._Error.hs

binary file changed (186 → absent bytes)

− src/Control/Effects/._NonDet.hs

binary file changed (186 → absent bytes)

− src/Control/Effects/._State.hs

binary file changed (186 → absent bytes)

− src/Control/Effects/._Writer.hs

binary file changed (186 → absent bytes)

src/Control/Effects/Cont.hs view
@@ -1,13 +1,13 @@-{-# LANGUAGE FlexibleContexts #-}-module Control.Effects.Cont where--import Control.Effects--shift :: AutoLift r m n => Effect r m -> ((m a -> m r) -> m r) -> n a-shift p c = operation p $ \k -> c (>>= k)--reset :: Monad m => Handler a a m a-reset = Handler-  { ret = return-  , fin = return+{-# LANGUAGE FlexibleContexts #-}
+module Control.Effects.Cont where
+
+import Control.Effects
+
+shift :: AutoLift r m n => Effect r m -> ((m a -> m r) -> m r) -> n a
+shift p c = operation p $ \k -> c (>>= k)
+
+reset :: Monad m => Handler a a m a
+reset = Handler
+  { ret = return
+  , fin = return
   }
src/Control/Effects/Either.hs view
@@ -1,14 +1,14 @@-{-# LANGUAGE FlexibleContexts #-}-module Control.Effects.Either where--import Control.Effects-import Data.Void--throwEither :: AutoLift (Either e r) m n => Effect (Either e r) m -> e -> n Void-throwEither p e = operation p $ \_ -> return $ Left e--catchEither :: Monad m => (e -> m a) -> Handler (Either e a) a m a-catchEither h = Handler-  { ret = return . return-  , fin = either h return+{-# LANGUAGE FlexibleContexts #-}
+module Control.Effects.Either where
+
+import Control.Effects
+import Data.Void
+
+throwEither :: AutoLift (Either e r) m n => Effect (Either e r) m -> e -> n Void
+throwEither p e = operation p $ \_ -> return $ Left e
+
+catchEither :: Monad m => (e -> m a) -> Handler (Either e a) a m a
+catchEither h = Handler
+  { ret = return . return
+  , fin = either h return
   }
src/Control/Effects/Error.hs view
@@ -1,14 +1,14 @@-{-# LANGUAGE FlexibleContexts #-}-module Control.Effects.Error where--import Control.Effects-import Data.Void--throwError :: AutoLift ((e -> m r) -> m r) m n => Effect ((e -> m r) -> m r) m -> e -> n Void-throwError p e = operation p $ \_ -> return $ \h -> h e--catchError :: Monad m => (e -> m a) -> Handler ((e -> m a) -> m a) a m a-catchError h = Handler-  { ret = return . return . return-  , fin = \f -> f h+{-# LANGUAGE FlexibleContexts #-}
+module Control.Effects.Error where
+
+import Control.Effects
+import Data.Void
+
+throwError :: AutoLift ((e -> m r) -> m r) m n => Effect ((e -> m r) -> m r) m -> e -> n Void
+throwError p e = operation p $ \_ -> return $ \h -> h e
+
+catchError :: Monad m => (e -> m a) -> Handler ((e -> m a) -> m a) a m a
+catchError h = Handler
+  { ret = return . return . return
+  , fin = \f -> f h
   }
src/Control/Effects/NonDet.hs view
@@ -1,55 +1,58 @@-{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances #-}-module Control.Effects.NonDet (choose, dfs, set, alternatives, accumulate, bfs) where--import Control.Effects-import qualified Data.Set as Set-import Prelude hiding (foldr)-import Data.Foldable-import Data.Monoid-import Control.Applicative-import Control.Monad-import Control.Newtype--instance (Monad m, Monoid r) => Monoid (WrappedMonad m r) where-  mempty                              = WrapMonad $ return mempty-  mappend (WrapMonad a) (WrapMonad b) = WrapMonad $ liftM2 mappend a b--newtype WrappedAlt f a = WrapAlt (f a)-instance Newtype (WrappedAlt m a) (m a) where-  pack = WrapAlt-  unpack (WrapAlt a) = a-instance Alternative f => Monoid (WrappedAlt f a) where-  mempty                          = WrapAlt empty-  mappend (WrapAlt a) (WrapAlt b) = WrapAlt $ a <|> b--choose :: (AutoLift r m n, Monoid r, Foldable f) => Effect r m -> f a -> n a-choose p as = operation p $ \k -> ala' WrapMonad foldMap k as--dfs :: (Monad m, Monoid r) => (a -> r) -> Handler r r m a-dfs f = Handler-  { ret = return . f-  , fin = return-  }--set :: (Monad m, Ord a) => Handler (Set.Set a) (Set.Set a) m a-set = dfs Set.singleton--alternatives :: (Monad m, Alternative f) => Handler (WrappedAlt f a) (f a) m a-alternatives = accumulate (WrapAlt . pure)--accumulate :: (Monad m, Newtype n o) => (a -> n) -> Handler n o m a-accumulate f = Handler-  { ret = return . f-  , fin = return . unpack-  }--newtype BFS r = BFS { unBFS :: Int -> Maybe r }-instance Monoid r => Monoid (BFS r) where-  mempty                = BFS $ \d -> if d == 0 then Just mempty else Nothing-  BFS f `mappend` BFS g = BFS $ \d -> if d == 0 then f d else f d `mappend` g (d - 1)-instance Monoid r => Newtype (BFS r) r where-  pack r                = BFS $ \d -> if d == 0 then Just r else Nothing-  unpack (BFS f)        = loop 0 where loop d = maybe mempty (`mappend` loop (d + 1)) (f d)--bfs :: (Monad m, Monoid r) => (a -> r) -> Handler (BFS r) r m a+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances #-}
+module Control.Effects.NonDet (choose, guard, dfs, set, alternatives, accumulate, bfs) where
+
+import Control.Effects
+import qualified Data.Set as Set
+import Prelude hiding (foldr)
+import Data.Foldable
+import Data.Monoid
+import Control.Applicative
+import Control.Newtype
+
+instance (Applicative m, Monoid r) => Monoid (WrappedMonad m r) where
+  mempty                              = WrapMonad $ pure mempty
+  mappend (WrapMonad a) (WrapMonad b) = WrapMonad $ liftA2 mappend a b
+
+newtype WrappedAlt f a = WrapAlt (f a)
+instance Newtype (WrappedAlt m a) (m a) where
+  pack = WrapAlt
+  unpack (WrapAlt a) = a
+instance Alternative f => Monoid (WrappedAlt f a) where
+  mempty                          = WrapAlt empty
+  mappend (WrapAlt a) (WrapAlt b) = WrapAlt $ a <|> b
+
+choose :: (AutoLift r m n, Monoid r, Foldable f) => Effect r m -> f a -> n a
+choose p as = operation p $ \k -> ala' WrapMonad foldMap k as
+
+guard :: (Monoid r, AutoLift r m n) => Effect r m -> Bool -> n ()
+guard _ True = return ()
+guard p False = choose p []
+
+dfs :: (Monad m, Monoid r) => (a -> r) -> Handler r r m a
+dfs f = Handler
+  { ret = return . f
+  , fin = return
+  }
+
+set :: (Monad m, Ord a) => Handler (Set.Set a) (Set.Set a) m a
+set = dfs Set.singleton
+
+alternatives :: (Monad m, Alternative f) => Handler (WrappedAlt f a) (f a) m a
+alternatives = accumulate (WrapAlt . pure)
+
+accumulate :: (Monad m, Newtype n o) => (a -> n) -> Handler n o m a
+accumulate f = Handler
+  { ret = return . f
+  , fin = return . unpack
+  }
+
+newtype BFS r = BFS (Int -> Maybe r)
+instance Monoid r => Monoid (BFS r) where
+  mempty                = BFS $ \d -> if d == 0 then Just mempty else Nothing
+  BFS f `mappend` BFS g = BFS $ \d -> if d == 0 then f d else f d `mappend` g (d - 1)
+instance Monoid r => Newtype (BFS r) r where
+  pack r                = BFS $ \d -> if d == 0 then Just r else Nothing
+  unpack (BFS f)        = loop 0 where loop d = maybe mempty (`mappend` loop (d + 1)) (f d)
+
+bfs :: (Monad m, Monoid r) => (a -> r) -> Handler (BFS r) r m a
 bfs f = accumulate (pack . f)
src/Control/Effects/State.hs view
@@ -1,35 +1,35 @@-{-# LANGUAGE FlexibleContexts #-}-module Control.Effects.State where--import Control.Effects--type State s m a = s -> m a--get :: AutoLift (State s m a) m n => Effect (State s m a) m -> n s-get p = operation p $ \k -> return $ \s -> do r <- k s; r s--put :: AutoLift (State s m a) m n => Effect (State s m a) m -> s -> n ()-put p s = operation p $ \k -> return $ \_ -> do r <- k (); r s--infixr 3 =:-(=:) :: AutoLift (State s m a) m n => Effect (State s m a) m -> n s -> n ()-p =: m = m >>= put p--modify :: AutoLift (State s m a) m n => Effect (State s m a) m -> (s -> s) -> n ()-modify p f = do-  v <- get p-  put p (f v)--local :: AutoLift (State s m a) m n => Effect (State s m a) m -> (s -> s) -> n b -> n b-local p f m = do-  v <- get p-  put p (f v)-  r <- m-  put p v-  return r--ref :: Monad m => s -> Handler (State s m a) a m a-ref s_init = Handler-  { ret = return . return . return-  , fin = \f -> f s_init+{-# LANGUAGE FlexibleContexts #-}
+module Control.Effects.State where
+
+import Control.Effects
+
+type State s m a = s -> m a
+
+get :: AutoLift (State s m a) m n => Effect (State s m a) m -> n s
+get p = operation p $ \k -> return $ \s -> do r <- k s; r s
+
+put :: AutoLift (State s m a) m n => Effect (State s m a) m -> s -> n ()
+put p s = operation p $ \k -> return $ \_ -> do r <- k (); r s
+
+infixr 3 =:
+(=:) :: AutoLift (State s m a) m n => Effect (State s m a) m -> n s -> n ()
+p =: m = m >>= put p
+
+modify :: AutoLift (State s m a) m n => Effect (State s m a) m -> (s -> s) -> n ()
+modify p f = do
+  v <- get p
+  put p (f v)
+
+local :: AutoLift (State s m a) m n => Effect (State s m a) m -> (s -> s) -> n b -> n b
+local p f m = do
+  v <- get p
+  put p (f v)
+  r <- m
+  put p v
+  return r
+
+ref :: Monad m => s -> Handler (State s m a) a m a
+ref s_init = Handler
+  { ret = return . return . return
+  , fin = \f -> f s_init
   }
src/Control/Effects/Writer.hs view
@@ -1,16 +1,16 @@-{-# LANGUAGE FlexibleContexts #-}-module Control.Effects.Writer where--import Control.Effects-import Data.Monoid--tell :: (AutoLift (w, r) m n, Monoid w) => Effect (w, r) m -> w -> n ()-tell p v = operation p $ \k -> do-  ~(w, r) <- k ()-  return (mappend v w, r)--writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a-writer = Handler-  { ret = \a -> return (mempty, a)-  , fin = return+{-# LANGUAGE FlexibleContexts #-}
+module Control.Effects.Writer where
+
+import Control.Effects
+import Data.Monoid
+
+tell :: (AutoLift (w, r) m n, Monoid w) => Effect (w, r) m -> w -> n ()
+tell p v = operation p $ \k -> do
+  ~(w, r) <- k ()
+  return (mappend v w, r)
+
+writer :: (Monad m, Monoid w) => Handler (w, a) (w, a) m a
+writer = Handler
+  { ret = \a -> return (mempty, a)
+  , fin = return
   }