Verified Commit f44b4d58 authored by Justin Andresen's avatar Justin Andresen
Browse files

Add test project for `freer-simple`

parent da071862
### Files and directories generated by Cabal ###
dist
dist-newstyle
.ghc.environment.*
Copyright (c) 2020, Justin Andresen <jan.dresen.95@gmail.com>, Kiel University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the copyright holder nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import Distribution.Simple
main = defaultMain
-- Cabal configuration file for this package.
packages: mapro-polysemy-test.cabal
-- Configure this package to compile only if there are no compile time
-- warnings in production mode. To disable fatal warnings during development
-- pass `--ghc-option=-Wwarn` to `cabal`.
package mapro-polysemy-test
ghc-options: -Werror
cabal-version: 2.4
-- Initial package description 'mapro-freer-simple-test.cabal' generated
-- by 'cabal init'. For further documentation, see
-- http://haskell.org/cabal/users-guide/
name: mapro-freer-simple-test
version: 0.1.0.0
synopsis: Cabal test project for the freer-simple library.
-- description:
-- bug-reports:
license: BSD-3-Clause
license-file: LICENSE
author: Justin Andresen
maintainer: jan.dresen.95@gmail.com
copyright: (c) 2020, Justin Andresen, Kiel University
-- category:
library
-- exposed-modules:
-- other-extensions:
build-depends: base ^>=4.12.0.0
, freer-simple
hs-source-dirs: src
default-language: Haskell2010
other-modules: MyEffects
, MyHandlers
, MyProgs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
module MyEffects where
import Control.Monad.Freer
import Control.Monad.Freer.TH
data MyState s r where
MyGet :: MyState s s
MyPut :: s -> MyState s ()
makeEffect ''MyState
data MyLog r where
MyLog :: Show a => a -> MyLog ()
makeEffect ''MyLog
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
-- Additional language extensions.
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module MyHandlers where
import Control.Monad.Freer
import Control.Monad.Freer.State
import MyEffects
-- It is not possible to write stateful effect handlers in freer-simple
-- without importing utility functions. Handling of the state has to
-- be reinterpreted in terms of the built-in state effect.
runMyState :: s -> Eff (MyState s ': effs) a -> Eff effs (a, s)
runMyState initialState = runState initialState . reinterpret \case
MyGet -> get
MyPut s' -> put s'
-- This handler is a bit more difficult to implement than in Polysemy because
-- freer-simple does not have a compiler plugin to add the type application
-- automatically.
logMyState
:: forall s a effs
. (Members '[MyState s, MyLog] effs, Show s)
=> Eff effs a
-> Eff effs a
logMyState = interpose @(MyState s) \case
MyGet -> myGet
MyPut s' -> do
myLog s'
myPut s'
printLog :: LastMember IO effs => Eff (MyLog ': effs) a -> Eff effs a
printLog = interpretM \case
MyLog msg -> putStrLn ("Info: " ++ show msg)
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeApplications #-}
module MyProgs where
import Control.Monad.Freer
import MyEffects
import MyHandlers
-- In contrast to Polysemy, we need type applications (or a type signature)
-- here to tell GHC which type @n@ has. GHC knows only that @n@ must have
-- @Num@ and @Eq@ instances. In case of Polysemy, the plugin adds the type
-- annotations automatically.
myProg :: Member (MyState Int) r => Eff r Bool
myProg = do
n <- myGet @Int
myPut (2 * n)
m <- myGet
myPut (m - n)
n' <- myGet
return (n' == n)
myInitialState :: Int
myInitialState = 42
runMyProg :: IO (Bool, Int)
runMyProg = runM . runMyState myInitialState $ myProg
logMyProg :: IO (Bool, Int)
logMyProg =
runM . printLog . runMyState myInitialState . logMyState @Int $ myProg
cabal-version: 2.4
-- Initial package description 'mapro-effect-library-tests.cabal' generated
-- Initial package description 'mapro-polysemy-test.cabal' generated
-- by 'cabal init'. For further documentation, see
-- http://haskell.org/cabal/users-guide/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment