freer 0.2.2.5 → 0.2.2.6
raw patch · 3 files changed
+119/−1 lines, 3 filesPVP: minor bump suggested
API additions: PVP suggests at least a minor version bump
API changes (from Hackage documentation)
+ Control.Monad.Freer.Reader: asks :: (b -> a) -> Eff '[Reader b] a
Files
- freer.cabal +2/−1
- src/Control/Monad/Freer/Reader.hs +87/−0
- tests/Tests/Coroutine.hs +30/−0
freer.cabal view
@@ -1,5 +1,5 @@ name: freer-version: 0.2.2.5+version: 0.2.2.6 synopsis: Implementation of the Freer Monad license: BSD3 license-file: LICENSE@@ -75,6 +75,7 @@ hs-source-dirs: tests main-is: Tests.hs other-modules: Tests.Common+ , Tests.Coroutine , Tests.Exception , Tests.Fresh , Tests.NonDetEff
src/Control/Monad/Freer/Reader.hs view
@@ -24,8 +24,15 @@ Reader(..), ask,+ asks, runReader, local+ -- * Example 1: Simple Reader Usage+ -- $simpleReaderExample++ -- * Example 2: Modifying Reader Content With @local@+ -- $localExample+ ) where import Control.Monad.Freer.Internal@@ -38,6 +45,10 @@ ask :: (Member (Reader e) r) => Eff r e ask = send Reader +-- | Request a value from the environment and applys as function+asks :: (b -> a) -> Eff '[Reader b] a+asks f = ask >>= return . f+ -- | Handler for reader effects runReader :: Eff (Reader e ': r) w -> e -> Eff r w runReader m e = handleRelay return (\Reader k -> k e) m@@ -54,3 +65,79 @@ let h :: Reader e v -> Arr r v a -> Eff r a h Reader g = g e interpose return h m+++{- $simpleReaderExample++In this example the @Reader@ monad provides access to variable bindings.+Bindings are a @Map@ of integer variables.+The variable @count@ contains number of variables in the bindings.+You can see how to run a Reader effect and retrieve data from it+with 'runReader', how to access the Reader data with 'ask' and 'asks'.++>import Control.Monad.Freer+>import Control.Monad.Freer.Reader+>import Data.Map as Map+>import Data.Maybe+>+>type Bindings = Map String Int+>+>asks :: (b -> a) -> Eff '[Reader b] a+>asks f = ask >>= return . f+>+>-- Returns True if the "count" variable contains correct bindings size.+>isCountCorrect :: Bindings -> Bool+>isCountCorrect bindings = run $ runReader calc_isCountCorrect bindings+>+>-- The Reader effect, which implements this complicated check.+>calc_isCountCorrect :: Eff '[Reader Bindings] Bool+>calc_isCountCorrect = do+> count <- asks (lookupVar "count")+> bindings <- (ask :: Eff '[Reader Bindings] Bindings)+> return (count == (Map.size bindings))+>+>-- The selector function to use with 'asks'.+>-- Returns value of the variable with specified name.+>lookupVar :: String -> Bindings -> Int+>lookupVar name bindings = fromJust (Map.lookup name bindings)+>+>sampleBindings :: Map.Map String Int+>sampleBindings = Map.fromList [("count",3), ("1",1), ("b",2)]+>+>main = do+> putStr $ "Count is correct for bindings " ++ (show sampleBindings) ++ ": "+> putStrLn $ show (isCountCorrect sampleBindings)+-}++{- $localExample++Shows how to modify Reader content with 'local'.++> import Control.Monad.Freer+> import Control.Monad.Freer.Reader+>+> import Data.Map as Map+> import Data.Maybe+>+> type Bindings = Map String Int+>+> asks :: (b -> a) -> Eff '[Reader b] a+> asks f = ask >>= return . f+>+> calculateContentLen :: Eff '[Reader String] Int+> calculateContentLen = do+> content <- (ask :: Eff '[Reader String] String)+> return (length content)+>+> -- Calls calculateContentLen after adding a prefix to the Reader content.+> calculateModifiedContentLen :: Eff '[Reader String] Int+> calculateModifiedContentLen = local ("Prefix " ++) calculateContentLen+>+> main :: IO ()+> main = do+> let s = "12345";+> let modifiedLen = run $ runReader calculateModifiedContentLen s;+> let len = run $ runReader calculateContentLen s ;+> putStrLn $ "Modified 's' length: " ++ (show modifiedLen)+> putStrLn $ "Original 's' length: " ++ (show len)+-}
+ tests/Tests/Coroutine.hs view
@@ -0,0 +1,30 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE DataKinds #-}++module Tests.Coroutine (+ runTestCoroutine+) where++import Control.Monad+import Control.Monad.Freer+import Control.Monad.Freer.Coroutine+import Control.Monad.Freer.State++runTestCoroutine :: [Int] -> Int+runTestCoroutine list = snd $ run $ runState effTestCoroutine 0+ where+ testCoroutine :: (Members '[Yield () Int, State Int] r) => Eff r ()+ testCoroutine = do+ -- yield for two elements and hope they're both odd+ b <- (&&)+ <$> yield () (even :: Int -> Bool)+ <*> yield () (even :: Int -> Bool)+ unless b (modify ((+1) :: Int -> Int) >> testCoroutine)++ effTestCoroutine = do+ status <- runC testCoroutine+ handleStatus list status+ where+ handleStatus _ Done = return ()+ handleStatus (i:is) (Continue () k) = k i >>= handleStatus is+ handleStatus [] _ = return ()