cleff: Fast and concise extensible effects

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Please see the README on GitHub at https://github.com/re-xyr/cleff#readme


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.2.0.0, 0.2.1.0, 0.3.0.0, 0.3.0.1, 0.3.1.0, 0.3.2.0, 0.3.2.0, 0.3.3.0
Change log CHANGELOG.md
Dependencies atomic-primops (>=0.8 && <0.9), base (>=4.12 && <4.17), containers (>=0.5 && <0.7), exceptions (>=0.10 && <0.11), microlens (>=0.1 && <0.5), monad-control (>=1 && <1.1), primitive (>=0.6.4 && <0.8), template-haskell (>=2.14 && <2.19), th-abstraction (>=0.2 && <0.5), transformers-base (>=0.4 && <0.5), unliftio (>=0.2.4 && <0.3) [details]
License BSD-3-Clause
Copyright 2021 Xy Ren
Author Xy Ren
Maintainer xy.r@outlook.com
Category Control, Effect, Language
Home page https://github.com/re-xyr/cleff#readme
Bug tracker https://github.com/re-xyr/cleff/issues
Source repo head: git clone https://github.com/re-xyr/cleff
Uploaded by daylily at 2022-03-11T08:45:15Z

Modules

[Index]

Flags

Manual Flags

NameDescriptionDefault
dynamic-ioe

Make IOE a real effect. This is only for reference purposes and should not be enabled in production code.

Disabled

Use -f <flag> to enable a flag, or -f -<flag> to disable that flag. More info

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for cleff-0.3.2.0

[back to package description]

cleff - fast and concise extensible effects

GitHub Workflow Status Hackage

cleff is an extensible effects library for Haskell, with a focus on the balance of performance, expressiveness and ease of use. It provides a set of predefined effects that you can conveniently reuse in your program, as well as low-boilerplate mechanisms for defining and interpreting new domain-specific effects on your own.

In essence, cleff offers:

Example

This is the code that defines the classic Teletype effect. It only takes 20 lines to define the effect and two interpretations, one using stdio and another reading from and writing to a list:

import Cleff
import Cleff.Input
import Cleff.Output
import Cleff.State
import Data.Maybe (fromMaybe)

-- Effect definition
data Teletype :: Effect where
  ReadTTY :: Teletype m String
  WriteTTY :: String -> Teletype m ()
makeEffect ''Teletype

-- Effect Interpretation via IO
runTeletypeIO :: IOE :> es => Eff (Teletype : es) a -> Eff es a
runTeletypeIO = interpretIO \case
  ReadTTY    -> getLine
  WriteTTY s -> putStrLn s

-- Effect interpretation via other pure effects
runTeletypePure :: [String] -> Eff (Teletype : es) w -> Eff es [String]
runTeletypePure tty = fmap (reverse . snd)
  . runState [] . outputToListState
  . runState tty . inputToListState
  . reinterpret2 \case
    ReadTTY -> fromMaybe "" <$> input
    WriteTTY msg -> output msg

-- Using the effect

echo :: Teletype :> es => Eff es ()
echo = do
  x <- readTTY
  if null x then pure ()
    else writeTTY x >> echo

echoPure :: [String] -> [String]
echoPure input = runPure $ runTeletypePure input echo

main :: IO ()
main = runIOE $ runTeletypeIO echo

See example/ for more examples.

Benchmarks

These are the results of the effect-zoo microbenchmarks, compiled by GHC 8.10.7. Keep in mind that these are very short and synthetic programs, and may or may not tell the accurate performance characteristics of different effect libraries in real use:

Differences from effectful

If you know about effectful, you may notice that cleff and effectful seem to make many similar claims and have a similar underlying implementation. In microbenchmarks, cleff is slightly behind effectful. This may make you confused about the differences between the two libraries. To put it simply, cleff has a more versatile and expressive effect interpretation mechanism, and a lighter weight API. In contrast, effectful gains its performance advantage by providing static dispatch for some internal effects, which means they cannot have multiple interpretations.

References

These are the useful resources that inspired this library's design and implementation.

Papers:

Libraries:

Talks:

Blog posts: