Freer: Extensible Effects with Freer Monads

Freer is an implementation of "Freer Monads, More Extensible Effects". Much of the implementation is a repackaging and cleaning up of the reference materials provided here.

Features

The key features of Freer are:

  • An efficient effect system for Haskell as a library
  • Implementations for several common Haskell monad instances: Reader Writer State StateRW: State in terms of Reader/Writer Trace Exception
  • Core components for defining your own Effects

Example: Teletype DSL

Here's what using Freer looks like:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
module Teletype where

import Control.Monad.Freer
import Control.Monad.Freer.Internal
import System.Exit hiding (ExitSuccess)

--------------------------------------------------------------------------------
                          -- Effect Model --
--------------------------------------------------------------------------------
data Teletype s where
  PutStrLn    :: String -> Teletype ()
  GetLine     :: Teletype String
  ExitSuccess :: Teletype ()

putStrLn' :: Member Teletype r => String -> Eff r ()
putStrLn' = send . PutStrLn

getLine'  :: Member Teletype r => Eff r String
getLine' = send GetLine

exitSuccess' :: Member Teletype r => Eff r ()
exitSuccess' = send ExitSuccess

--------------------------------------------------------------------------------
                     -- Effectful Interpreter --
--------------------------------------------------------------------------------
runTeletype :: Eff '[Teletype] w -> IO w
runTeletype (Val x) = return x
runTeletype (E u q) = case extract u of
              (PutStrLn msg) -> putStrLn msg  >> runTeletype (qApp q ())
              GetLine        -> getLine      >>= \s -> runTeletype (qApp q s)
              ExitSuccess    -> exitSuccess

--------------------------------------------------------------------------------
                        -- Pure Interpreter --
--------------------------------------------------------------------------------
runTeletypePure :: [String] -> Eff '[Teletype] w -> [String]
runTeletypePure inputs req =
  reverse . snd $ run (handleRelayS (inputs, []) (\s _ -> pure s) go req)
  where
    go :: ([String], [String])
       -> Teletype v
       -> (([String], [String]) -> Arr '[] v ([String], [String]))
       -> Eff '[] ([String], [String])
    go (is, os) (PutStrLn msg) q = q (is, msg : os) ()
    go (i:is, os) GetLine q = q (is, os) i
    go ([], _) GetLine _ = error "Not enough lines"
    go (_, os) ExitSuccess _ = pure ([], os)

Contributing

Contributions are welcome! Documentation, examples, code, and feedback - they all help.

Be sure to review the included code of conduct. This project adheres to the Contributor's Covenant. By participating in this project you agree to abide by its terms.

Developer Setup

The easiest way to start contributing is to install stack. stack can install GHC/Haskell for you, and automates common developer tasks.

The key commands are:

  • stack setup : install GHC
  • stack build
  • stack clean
  • stack haddock : builds documentation
  • stack test
  • stack bench
  • stack ghci : start a REPL instance

Licensing

This project is distrubted under a BSD3 license. See the included LICENSE file for more details.

Acknowledgements

This package would not be possible without the paper and the reference implementation. In particular:

There will be deviations from the source.

Changes

0.2.4.1 (November 25, 2016)

  • Restore GHC (7.8, 7.10) compatibility

0.2.4.0 (November 25, 2016)

  • Internal reorg In particular, hide implementation details in Union.Internal Rewrite interpreters in terms of extract instead of decomp

0.2.3.0 (June 25, 2016)

  • Add GHC 8 support

0.2.2.2 (Sep. 14, 2015)

  • Use local data Nat for Data.Open.Union * Using GHC.TypeLits lead to overlapping instances

0.2.2.1 (Sep. 14, 2015)

  • Document ALL THE THINGS

0.2.2.0 (Sep. 13, 2015)

  • Add bench suite

0.2.1.0 (Sep. 13, 2015)

  • Add test suite

0.2.0.2 (Sep. 12, 2015)

  • Clean up language extensions per file
  • Add Teletype DSL to the README

0.2.0.1 (Sep. 12, 2015)

  • Add Teletype DSL example
  • Expose send in public interface

0.2.0.0 (Sep. 12, 2015)

  • Implement NonDetEff
  • Separate Cut/Coroutine out from Internals * Partial implementation: won't compile yet
  • Extract remaining examples from Internal comments

0.1.1.0 (Sep. 12, 2015)

  • Warnings clean up
  • Examples separated from primary implementation
  • Initial project documentation added

0.1.0.0 (Sep. 12, 2015)

  • Initial release
Depends on:
Used by 1 package:
comments powered byDisqus