Safe Haskell | Safe |
---|---|
Language | Haskell2010 |
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 and requires some language extensions:
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MonoLocalBinds #-} import Control.Eff import Control.Eff.Reader.Lazy import Control.Eff.Writer.Lazy import Control.Eff.State.Lazy import Control.Eff.Exception
If you want to see what each extension is good for, you can disable it and see what GHC will complain about.
Synopsis
- tooBig :: Member (Exc String) r => Int -> Eff r Int
- runTooBig :: Int -> Either String Int
- popState :: Member (State [Int]) r => Eff r (Maybe Int)
- runPopState :: [Int] -> (Maybe Int, [Int])
- oneMore :: Member (Reader Int) r => Eff r Int
- runOneMore :: Int -> Int
- something :: (Member (Reader Float) r, Member (State [Integer]) r, Member (Exc Float) r) => Eff r Integer
- runSomething1 :: [Integer] -> Float -> Either Float (Integer, [Integer])
- runSomething2 :: [Integer] -> Float -> (Either Float Integer, [Integer])
- module Control.Eff.Reader.Lazy
- module Control.Eff.State.Lazy
- module Control.Eff.Exception
Examples
tooBig :: Member (Exc String) r => Int -> Eff r Int Source #
an effectful function that can throw an error
tooBig i = do when (i > 100) $ throwError $ show i return i
runTooBig :: Int -> Either String Int Source #
run the tooBig
effect based on a provided Int.
runTooBig i = run . runError $ tooBig i
>>>
runTooBig 1
Right 1
>>>
runTooBig 200
Left "200"
popState :: Member (State [Int]) r => Eff r (Maybe Int) Source #
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
runPopState :: [Int] -> (Maybe Int, [Int]) Source #
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,[])
oneMore :: Member (Reader Int) r => Eff r Int Source #
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
runOneMore :: Int -> Int Source #
Run the oneMore
effectful function by giving it a value to read.
runOneMore i = run . runReader i $ oneMore
>>>
runOneMore 1
2
something :: (Member (Reader Float) r, Member (State [Integer]) r, Member (Exc Float) r) => Eff r Integer Source #
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
runSomething1 :: [Integer] -> Float -> Either Float (Integer, [Integer]) Source #
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])
runSomething2 :: [Integer] -> Float -> (Either Float Integer, [Integer]) Source #
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])
Imported effect modules
module Control.Eff.Reader.Lazy
module Control.Eff.State.Lazy
module Control.Eff.Exception