freer-simple

Implementation of a friendly effect system for Haskell.

https://github.com/lexi-lambda/freer-simple#readme

Version on this page:1.2.1.1@rev:1
LTS Haskell 23.0:1.2.1.2@rev:2
Stackage Nightly 2024-12-09:1.2.1.2@rev:2
Latest on Hackage:1.2.1.2@rev:2

See all snapshots freer-simple appears in

BSD-3-Clause licensed by Allele Dev, Ixcom Core Team, Alexis King, and other contributors
Maintained by Alexis King
This version can be pinned in stack with:freer-simple-1.2.1.1@sha256:2419be815725c8e3f55947603da00ee4978396ed2480ea3dacf8227d36aa8781,4950

Freer: Extensible Effects with Freer Monads Build Status

Description

The freer-simple library (a fork of freer-effects) is an implementation of an 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-simple are:

  • An efficient effect system for Haskell as a library.
  • Implementations for several common Haskell monads as effects:
    • Reader
    • Writer
    • State
    • Trace
    • Error
  • Core components for defining your own Effects.

Example: Console DSL

Here’s what using freer-simple looks like:

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

import Control.Monad.Freer
import Control.Monad.Freer.Error
import Control.Monad.Freer.State
import Control.Monad.Freer.Writer
import System.Exit hiding (ExitCode(ExitSuccess))

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

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

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

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

--------------------------------------------------------------------------------
                          -- Effectful Interpreter --
--------------------------------------------------------------------------------
runConsole :: Eff '[Console, IO] a -> IO a
runConsole = runM . interpretM (\case
  PutStrLn msg -> putStrLn msg
  GetLine -> getLine
  ExitSuccess -> exitSuccess)

--------------------------------------------------------------------------------
                             -- Pure Interpreter --
--------------------------------------------------------------------------------
runConsolePure :: [String] -> Eff '[Console] w -> [String]
runConsolePure inputs req = snd . fst $
    run (runWriter (runState inputs (runError (reinterpret3 go req))))
  where
    go :: Console v -> Eff '[Error (), State [String], Writer [String]] v
    go (PutStrLn msg) = tell [msg]
    go GetLine = get >>= \case
      [] -> error "not enough lines"
      (x:xs) -> put xs >> pure x
    go ExitSuccess = throwError ()

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

More information about stack can be found in its documentation.

Licensing

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

Acknowledgements

The freer-simple package started as a fork of freer-effects by Ixperta Solutions, which in turn is a fork of freer by Allele Dev. All implementations are based on the paper and reference implementation by Oleg Kiselyov. In particular:

There will be deviations from the source.

Changes

1.2.1.1 (October 4th, 2019)

  • Loosened bounds on template-haskell (#29).
  • Made some minor internal changes to better support GHC 8.8.

1.2.1.0 (November 15th, 2018)

  • Improved makeEffect from Control.Monad.Freer.TH to support more datatypes (#17).

1.2.0.0 (October 23rd, 2018)

  • Added Control.Monad.Freer.TH, which provides a makeEffect function that automatically generates boilerplate operations using send for an effect (#15).

1.1.0.0 (February 20th, 2018)

  • Changed the implementation of LastMember to avoid an issue similar to the one with Member fixed in 1.0.1.1 that could cause the constraint to unnecessarily fail to solve (#6).
  • Changed the order of the type variables in interpretM to be more consistent with other functions (only relevant in combination with TypeApplications).
  • Re-exported (~>) from Control.Natural through Control.Monad.Freer.

1.0.1.1 (January 31st, 2018)

  • Fixed a bug that could cause Member constraints to erroneously fail to solve (#3).

1.0.1.0 (January 27th, 2018)

  • Added subsume to Control.Monad.Freer for deduplicating effects.
  • Added gets to Control.Monad.Freer.State (#1).

1.0.0.0 (December 7th, 2017)

  • Initial release.