effects 0.2 → 0.2.1
raw patch · 15 files changed
+157/−10 lines, 15 filesbinary-added
Files
- ._LICENSE binary
- ._README.md binary
- ._effects.cabal binary
- ._examples.hs binary
- README.md +28/−0
- effects.cabal +1/−1
- examples.hs +109/−0
- src/Control/._Effects.hs binary
- src/Control/Effects.hs +19/−9
- src/Control/Effects/._Cont.hs binary
- src/Control/Effects/._Either.hs binary
- src/Control/Effects/._Error.hs binary
- src/Control/Effects/._NonDet.hs binary
- src/Control/Effects/._State.hs binary
- src/Control/Effects/._Writer.hs binary
+ ._LICENSE view
binary file changed (absent → 185 bytes)
+ ._README.md view
binary file changed (absent → 187 bytes)
+ ._effects.cabal view
binary file changed (absent → 186 bytes)
+ ._examples.hs view
binary file changed (absent → 187 bytes)
+ README.md view
@@ -0,0 +1,28 @@+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
effects.cabal view
@@ -1,5 +1,5 @@ name: effects-version: 0.2+version: 0.2.1 synopsis: Computational Effects description: Control.Effects is a library for programming with effects, like in the the Eff language by
+ examples.hs view
@@ -0,0 +1,109 @@+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
+ src/Control/._Effects.hs view
binary file changed (absent → 187 bytes)
src/Control/Effects.hs view
@@ -15,9 +15,9 @@ , base -- * Effects machinery -- $macdoc- , Layer- , Base- , Pure+ , Layer(..)+ , Base(..)+ , Pure(..) , Effect , AutoLift , AutoLiftBase@@ -25,9 +25,11 @@ ) 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'.+-- Here's an example how to use the state effect from 'Control.Effects.State': -- -- > example :: Int -- > example = run $ do@@ -47,7 +49,7 @@ -- $defdoc--- Here's and example how to define the state effect from 'Control.Effects.Writer'.+-- 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@@ -63,7 +65,7 @@ -- | 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 narmally be left polymorphic, it's the monad that handles the other effects.+-- 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@@ -76,7 +78,7 @@ -- $basedoc--- The effects are layered on top of a base monad. Here's an example how to use `IO` as a base monad.+-- 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@@ -105,16 +107,24 @@ -- (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 r m) where+instance Functor (Layer e m) where fmap f m = Layer $ \k -> runLayer m (k . f) -instance Applicative (Layer r m) where+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.
+ src/Control/Effects/._Cont.hs view
binary file changed (absent → 186 bytes)
+ src/Control/Effects/._Either.hs view
binary file changed (absent → 186 bytes)
+ src/Control/Effects/._Error.hs view
binary file changed (absent → 186 bytes)
+ src/Control/Effects/._NonDet.hs view
binary file changed (absent → 186 bytes)
+ src/Control/Effects/._State.hs view
binary file changed (absent → 186 bytes)
+ src/Control/Effects/._Writer.hs view
binary file changed (absent → 186 bytes)