packages feed

extensible-effects 2.6.2.0 → 2.6.3.0

raw patch · 5 files changed

+239/−15 lines, 5 filesdep +doctestPVP ok

version bump matches the API change (PVP)

Dependencies added: doctest

API changes (from Hackage documentation)

+ Control.Eff.QuickStart: oneMore :: Member (Reader Int) r => Eff r Int
+ Control.Eff.QuickStart: popState :: Member (State [Int]) r => Eff r (Maybe Int)
+ Control.Eff.QuickStart: runOneMore :: Int -> Int
+ Control.Eff.QuickStart: runPopState :: [Int] -> (Maybe Int, [Int])
+ Control.Eff.QuickStart: runSomething1 :: [Integer] -> Float -> Either Float (Integer, [Integer])
+ Control.Eff.QuickStart: runSomething2 :: [Integer] -> Float -> (Either Float Integer, [Integer])
+ Control.Eff.QuickStart: runTooBig :: Int -> Either String Int
+ Control.Eff.QuickStart: something :: (Member (Reader Float) r, Member (State [Integer]) r, Member (Exc Float) r) => Eff r Integer
+ Control.Eff.QuickStart: tooBig :: Member (Exc String) r => Int -> Eff r Int

Files

README.md view
@@ -1,5 +1,5 @@ -# Extensible effects+# Extensible effects (![Hackage](https://img.shields.io/hackage/v/extensible-effects.svg))  [![Build Status](https://travis-ci.org/suhailshergill/extensible-effects.svg?branch=master)](https://travis-ci.org/suhailshergill/extensible-effects) [![Join the chat at https://gitter.im/suhailshergill/extensible-effects](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/suhailshergill/extensible-effects?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)@@ -25,19 +25,15 @@  To experiment with this library, it is suggested to write some lines within `ghci`.-This section will include some code-examples, which you should try on your own!  Recommended Procedure: -1. add `extensible-effects` as a dependency to a existing cabal or stack project-or `git clone https://github.com/suhailshergill/extensible-effects.git`-2. start `stack ghci` or `cabal repl`-3. import some library modules as described in this section--*examples are a work in progress and there will be some Quickstart module to go-along the guide here*--*examples...*+1. get `extensible-effects` by doing one of the following:+  * add `extensible-effects` as a dependency to a existing cabal or stack project+  * `git clone https://github.com/suhailshergill/extensible-effects.git`+2. start `stack ghci` or `cabal repl` inside the project+3. import `Control.Eff` and `Control.Eff.QuickStart`+4. start with the examples provided in the documentation of the `Control.Eff.QuickStart` module  ## Tour through Extensible Effects @@ -83,7 +79,7 @@ Each has its own module that provide the same interface. By importing one or the other, it can be controlled if the effect is strict or lazy in its inputs and outputs.-Note that this changes the strictness of that effect only.+Unless required otherwise, it is suggested to use the lazy variants.  In this section, only the core functions associated with an effect are presented.@@ -196,7 +192,7 @@ run1 = run . runState initalState . runError $ myComp  run2 :: Either e (a, s)-runs = run . runError . runState initalState $ myComp+run2 = run . runError . runState initalState $ myComp ```  However, the order of the handlers does matter for the final result.@@ -220,6 +216,10 @@ possible to use the type operator `<::` and write `[ Exc e, State s ] <:: r => ...`, which has the same meaning. +It might be convenient to include the necessary language extensions and the+disabling of the class-constriant warnings in the cabal-file of your project.+*Explanation is work in progress*+ ## Other Effects  *work in progress*@@ -262,6 +262,13 @@ ## Writing your own Effects and Handlers  *work in progress*++## Other packages++Some other packages may implement various effects. Here is a rather incomplete+list:++* [log-effect](http://hackage.haskell.org/package/log-effect)  ## Background 
extensible-effects.cabal view
@@ -6,7 +6,7 @@ -- PVP summary:      +-+------- breaking API changes --                   | | +----- non-breaking API additions --                   | | | +--- code changes with no API change-version:             2.6.2.0+version:             2.6.3.0  -- A short (one-line) description of the package. synopsis:            An Alternative to Monad Transformers@@ -84,6 +84,7 @@                        Control.Eff.Writer.Lazy                        Control.Eff.Writer.Strict                        Data.OpenUnion+                       Control.Eff.QuickStart    -- Modules included in this library but not exported.   other-modules:       Control.Eff.Internal@@ -175,6 +176,7 @@                 , Control.Eff.Trace.Test                 , Control.Eff.Writer.Lazy.Test                 , Control.Eff.Writer.Strict.Test+                , DoctestRun    ghc-options: -Wall   if impl(ghc >= 8.0)@@ -192,6 +194,7 @@               , test-framework-hunit == 0.3.*               , test-framework-quickcheck2 == 0.3.*               , test-framework-th >= 0.2+              , doctest               , extensible-effects    default-language:    Haskell2010
+ src/Control/Eff/QuickStart.hs view
@@ -0,0 +1,198 @@+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE FlexibleContexts #-}++-- | This module contains several tiny examples of how to use effects.+-- For technical details, see the documentation in the effect-modules.+--+-- Note that most examples given here are very small. For them,+-- using `Eff` monad is more complicated compared to a standard functional+-- approach.+-- The power of extensible effects lie in the fact that these computations can+-- be used to construct much more complicated programs by composing the little+-- pieces shown here.+--+-- This module imports and reexports modules from this library:+--+-- @+-- import Control.Eff+-- import Control.Eff.Reader.Lazy+-- import Control.Eff.Writer.Lazy+-- import Control.Eff.State.Lazy+-- import Control.Eff.Exception+-- @+--+module Control.Eff.QuickStart+  ( -- * Examples+    module Control.Eff.QuickStart+    -- * Imported effect modules+  , module Control.Eff.Reader.Lazy+  , module Control.Eff.State.Lazy+  , module Control.Eff.Exception+  ) where++import           Control.Eff+import           Control.Eff.Reader.Lazy+import           Control.Eff.State.Lazy+import           Control.Eff.Exception+import           Control.Monad                            ( when )+++-- | an effectful function that can throw an error+--+-- @+-- tooBig = do+--   when (i > 100) $ throwError $ show i+--   return i+-- @+tooBig :: Member (Exc String) r => Int -> Eff r Int+tooBig i = do+  when (i > 100) $ throwError $ show i+  return i++-- | run the @tooBig@ effect based on a provided Int.+--+-- @+-- runTooBig i = run . runError $ tooBig i+-- @+--+-- >>> runTooBig 1+-- Right 1+--+-- >>> runTooBig 200+-- Left "200"+runTooBig :: Int -> Either String Int+runTooBig i = run . runError $ tooBig i++-- | an effectul computation using state. The state is of type @[Int]@.+-- This function takes the head off the list, if it is there and return it.+-- If state is the empty list, then it stays the same and returns @Nothing@.+--+-- @+-- popState = do+--  stack <- get+--  case stack of+--    []       -> return Nothing+--    (x : xs) -> do+--      put xs+--      return $ Just x+-- @+popState :: Member (State [Int]) r => Eff r (Maybe Int)+popState = do+  stack <- get+  case stack of+    []       -> return Nothing+    (x : xs) -> do+      put xs+      return $ Just x++-- | run the popState effectful computation based on initial state. The+-- result-type is the result of the computation @Maybe Int@ together with the+-- state at the end of the computation @[Int]@+--+-- @+-- runPopState xs = run . runState xs $ popState+-- @+--+-- >>> runPopState  [1, 2, 3]+-- (Just 1,[2,3])+--+-- >>> runPopState []+-- (Nothing,[])+runPopState :: [Int] -> (Maybe Int, [Int])+runPopState xs = run . runState xs $ popState++-- | an effect that returns a number one more than the given+--+-- @+-- oneMore = do+--   x <- ask -- query the environment+--   return $ x + 1 -- add one to the asked value and return it+-- @+oneMore :: Member (Reader Int) r => Eff r Int+oneMore = do+  x <- ask+  return $ x + 1++-- | Run the @oneMore@ effectful function by giving it a value to read.+--+-- @+-- runOneMore i = run . runReader i $ oneMore+-- @+--+-- >>> runOneMore 1+-- 2+runOneMore :: Int -> Int+runOneMore i = run . runReader i $ oneMore++-- | An effectful computation with multiple effects:+--+-- * A value gets read+-- * an error can be thrown depending on the read value+-- * state gets read and transformed+--+-- All these effects are composed using the @Eff@ monad using the corresponding+-- Effect types.+--+-- @+-- something = do+--   readValue :: Float <- ask -- read a value from the environment+--   when (readValue < 0) $ throwError readValue  -- if the value is negative, throw an error+--   modify (\l -> (round readValue :: Integer) : l) -- add the rounded read element to the list+--   currentState :: [Integer] <- get -- get the state after the modification+--   return $ sum currentState -- sum the elements in the list and return that+-- @+something+  :: (Member (Reader Float) r, Member (State [Integer]) r, Member (Exc Float) r)+  => Eff r Integer+something = do+  readValue :: Float <- ask+  when (readValue < 0) $ throwError readValue+  modify (\l -> (round readValue :: Integer) : l)+  currentState :: [Integer] <- get+  return $ sum currentState++-- | Run the @someting@ effectful computation given in the previous function.+-- The handlers apply from bottom to top - so this is the reading direction.+--+-- @+-- runSomething1 initialState newValue =+--   run . -- run the Eff-monad with no effects left+--   runError . -- run the error part of the effect. This introduces the Either in the result.+--   runState initialState . -- handle the state-effect providing an initial state giving back a pair.+--   runReader newValue $ -- provide the computation with the dynamic value to read/ask for+--   something -- the computation - function+-- @+--+-- >>> runSomething1 [] (-0.5)+-- Left (-0.5)+--+-- >>> runSomething1 [2] 1.3+-- Right (3,[1,2])+runSomething1 :: [Integer] -> Float -> Either Float (Integer, [Integer])+runSomething1 initialState newValue =+  run . runError . runState initialState . runReader newValue $ something++-- | Run the @something@ effectful computation given above.+-- This has an alternative ordering of the effect-handlers.+--+-- The used effect-handlers are the same are used in slightly different order:+-- The @runState@ and @runError@ methods are swapped, which results in a+-- different output type and run-semantics.+--+-- @+-- runSomething1 initialState newValue =+--   run .+--   runState initialState .+--   runError .+--   runReader newValue $+--   something -- the computation - function+-- @+--+-- >>> runSomething2 [4] (-2.4)+-- (Left (-2.4),[4])+--+-- >>> runSomething2 [4] 5.9+-- (Right 10,[6,4])+runSomething2 :: [Integer] -> Float -> (Either Float Integer, [Integer])+runSomething2 initialState newValue =+  run . runState initialState . runError . runReader newValue $ something
+ test/DoctestRun.hs view
@@ -0,0 +1,13 @@+module DoctestRun where++import Test.DocTest (doctest)++runDocTest :: IO ()+runDocTest = do+  putStrLn ""+  putStrLn ""+  putStrLn "Doc Test..."+  doctest ["-i", "-XFlexibleContexts", "-XMultiParamTypeClasses", "-XFlexibleInstances", "-XGADTs", "-XScopedTypeVariables",+           "-isrc", "src/Control/Eff/QuickStart.hs"]+  putStrLn "Doc Test OK"+  putStrLn ""
test/Test.hs view
@@ -18,9 +18,12 @@ import qualified Control.Eff.Trace.Test import qualified Control.Eff.Writer.Lazy.Test import qualified Control.Eff.Writer.Strict.Test+import DoctestRun (runDocTest)  main :: IO ()-main = defaultMain testGroups+main = do+  runDocTest+  defaultMain testGroups  testGroups :: [Test] testGroups = []