packages feed

effet-0.3.0.2: examples/Example/Reader.hs

-- | Examples of the reader effect.
module Example.Reader where

-- base
import Control.Monad.IO.Class (MonadIO)
import Prelude         hiding (print)

-- hspec
import Test.Hspec (Spec, it, shouldBe)

-- effet
import Control.Effect.Identity
import Control.Effect.Reader

import Hspec (print, shouldPrint)

--- Example Programs -----------------------------------------------------------

-- | Returns the triple of the number in the reader.
triple :: Reader Int m => m Int
triple = do
  single <- ask
  double <- asks (*2)
  pure $ single + double

-- | Prints the triple and sixfold of the number in the reader.
printTripleSix :: (MonadIO m, Reader Int m) => m ()
printTripleSix = do
  t <- triple
  s <- local (*2) triple
  print t
  print s

-- | Prints the double of reader "bar" and the triple of reader "foo".
printFooBar :: (MonadIO m, Reader' "bar" Int m, Reader' "foo" Int m) => m ()
printFooBar =
  local' @"bar" (*2) $
  local' @"foo" (*3) $ do
    ask' @"bar" >>= print
    ask' @"foo" >>= print

--- Test Cases -----------------------------------------------------------------

spec :: Spec
spec = do
  it "evaluates triple" $
    ( runIdentity          -- result:  Int
    . runReader 22         -- result:  Monad m => m Int
    $ triple )             -- effects: Reader Int
      `shouldBe` 66
  it "evaluates printTripleSix" $
    runReader 10           -- result:  MonadIO m => m (), unified with IO ()
    printTripleSix         -- effects: MonadIO, Reader Int
      `shouldPrint` "30\n60\n"
  it "evaluates printFooBar" $
    ( runReader' @"bar" 20 -- result:  MonadIO m => m (), unified with IO ()
    . runReader' @"foo" 50 -- effects: MonadIO, Reader' "bar" Int
    $ printFooBar          -- effects: MonadIO, Reader' "bar" Int, Reader' "foo" Int
    ) `shouldPrint` "40\n150\n"