Freer Effects: Extensible Effects with Freer Monads

Haskell Programming Language BSD3 License

Hackage Hackage Dependencies Build

Description

Library freer-effects is an implementation of effect system for Haskell, which is based on the work of Oleg Kiselyov et al.:

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 monads as effects:
    • Reader
    • Writer
    • State
    • StateRW: State in terms of Reader/Writer.
    • Trace
    • Exception
  • Core components for defining your own Effects.

Example: Console DSL

Here's what using Freer looks like:

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

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

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

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

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

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

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

--------------------------------------------------------------------------------
                             -- Pure Interpreter --
--------------------------------------------------------------------------------
runConsolePure :: [String] -> Eff '[Console] w -> [String]
runConsolePure inputs req =
    reverse . snd $ run (handleRelayS (inputs, []) (\s _ -> pure s) go req)
  where
    go  :: ([String], [String])
        -> Console 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.

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 required version of GHC compiler
  • stack build – builds project, dependencies are automatically resolved
  • stack test – builds project, its tests, and executes the tests
  • stack bench – builds project, its benchmarks, and executes the benchamks
  • stack ghci – start a REPL instance with a project modules loaded
  • stack clean
  • stack haddock – builds documentation

For more information about stack tool can be found in its documentation.

Licensing

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

Acknowledgements

Package freer-effects started as a fork of freer authored by Allele Dev.

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

There will be deviations from the source.

Changes

Change Log

All notable changes to this project will be documented in this file.

0.3.0.1 (April 16, 2017)

  • Relax hlint version bounds and disable hlint tests in non-developer builds. #31

0.3.0.0 (March 06, 2017)

  • Package renamed to freer-effects to distinguish it from original freer. #4
  • Fix Could not deduce: effs ~ (r : rs) that may occur when using a Member contraint (a regression introduced in 0.2.4.0) freer!12
  • Add runNatS convenience function freer!13
  • Add evalState and execState convenience functions freer!14
  • Data constructors of Yield, CutFalse, Fresh, State and Trace are now exposed in addition to Exc, Reader and Writer
  • Generalised type signature of asks. #7
  • Renamed modules Data.Open.Union.* to Data.OpenUnion.*. #8
  • NonDetEff separated into its own module and renamed to NonDet. #11
  • Reimplement Union using http://okmij.org/ftp/Haskell/extensible/OpenUnion51.hs as a basis. #14
  • Renamed Teletype example DSL to Console.

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
  • Add runNat convenience function

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