mirror of
https://github.com/lexi-lambda/freer-simple.git
synced 2024-12-24 14:43:57 +03:00
da3b972379
Addresses #29
160 lines
5.8 KiB
Markdown
160 lines
5.8 KiB
Markdown
# Freer Effects: Extensible Effects with Freer Monads
|
||
|
||
[![Haskell Programming Language](https://img.shields.io/badge/language-Haskell-blue.svg)](http://www.haskell.org)
|
||
[![BSD3 License](http://img.shields.io/badge/license-BSD3-brightgreen.svg)](https://tldrlegal.com/license/bsd-3-clause-license-%28revised%29)
|
||
|
||
[![Hackage](http://img.shields.io/hackage/v/freer-effects.svg)](https://hackage.haskell.org/package/freer-effects)
|
||
[![Stackage LTS 8](http://stackage.org/package/freer-effects/badge/lts-8?label=lts-8)](http://stackage.org/nightly/package/freer-effects)
|
||
[![Stackage Nightly](http://stackage.org/package/freer-effects/badge/nightly?label=stackage)](http://stackage.org/nightly/package/freer-effects)
|
||
[![Hackage Dependencies](https://img.shields.io/hackage-deps/v/freer-effects.svg)](http://packdeps.haskellers.com/feed?needle=freer-effects)
|
||
[![Build](https://travis-ci.org/IxpertaSolutions/freer-effects.svg?branch=master)](https://travis-ci.org/IxpertaSolutions/freer-effects)
|
||
|
||
|
||
# Description
|
||
|
||
Library `freer-effects` (actively maintained fork of
|
||
[`freer`](http://hackage.haskell.org/package/freer)) is an implementation of
|
||
effect system for Haskell, which is based on the work of Oleg Kiselyov et al.:
|
||
|
||
* [Freer Monads, More Extensible Effects](http://okmij.org/ftp/Haskell/extensible/more.pdf)
|
||
* [Reflection without Remorse](http://okmij.org/ftp/Haskell/zseq.pdf)
|
||
* [Extensible Effects](http://okmij.org/ftp/Haskell/extensible/exteff.pdf)
|
||
|
||
Much of the implementation is a repackaging and cleaning up of the reference
|
||
materials provided [here](http://okmij.org/ftp/Haskell/extensible/).
|
||
|
||
|
||
# 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:
|
||
|
||
```haskell
|
||
{-# 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)
|
||
```
|
||
|
||
|
||
# Combining with Transformers
|
||
|
||
You already have some [`mtl`](http://hackage.haskell.org/package/mtl) code and
|
||
are afraid that combining effects with your current tranformer stack would not
|
||
be possible? Package
|
||
[`freer-effects-extra`](https://github.com/trskop/freer-effects-extra) has some
|
||
`mtl`-related and other goodies.
|
||
|
||
|
||
# Contributing
|
||
|
||
Contributions are welcome! Documentation, examples, code, and feedback - they
|
||
all help.
|
||
|
||
|
||
## Developer Setup
|
||
|
||
The easiest way to start contributing is to install
|
||
[stack](https://haskellstack.org/). 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](https://haskellstack.org/).
|
||
|
||
|
||
# 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](http://hackage.haskell.org/package/freer) authored by Allele Dev.
|
||
|
||
This package would not be possible without the paper and the reference
|
||
implementation. In particular:
|
||
|
||
* `Data.OpenUnion` maps to
|
||
[OpenUnion51.hs](http://okmij.org/ftp/Haskell/extensible/OpenUnion51.hs)
|
||
* `Data.FTCQueue` maps to
|
||
[FTCQueue1](http://okmij.org/ftp/Haskell/extensible/FTCQueue1.hs)
|
||
* `Control.Monad.Freer*` maps to
|
||
[Eff1.hs](http://okmij.org/ftp/Haskell/extensible/Eff1.hs)
|
||
|
||
There will be deviations from the source.
|