simple-effects-0.13.0.0: simple-effects.cabal
name: simple-effects
version: 0.13.0.0
synopsis: A simple effect system that integrates with MTL
description:
Some of the things you can do with this package:
.
* Declare and check which side-effects your function uses
* Dependency injection
* Test effectful code
* Avoid the \(n \times k\) instance problem
* Define custom effects with very little programming overhead
.
=== Declare and check which side-effects your function uses
.
The library provides a nice, declarative way of specifying exactly what your monadic function
does.
.
> getProductAndWriteToFile :: MonadEffects '[Database, FileSystem] m => ProductId -> FilePath -> m ()
.
This way you can be sure that your @harmlessFunction@ doesn't do unexpected things behind your
back. The compiler makes sure that all the effects are accounted for in the function's type.
.
=== Dependency injection
.
Functions are not tied to any specific implementation of an effect meaning you can swap out
different implementations without changing your code. Code like this
.
> myFunction :: MonadEffects '[Time, Logging] m => m ()
> myFunction = do
> t <- getCurrentTime
> log (show t)
.
is effectively the same as
.
> myFunction :: Monad m => m ZonedTime -> (String -> m ()) -> m ()
> myFunction getCurrentTime log = do
> t <- getCurrentTime
> log (show t)
.
but the library does all the parameter passing for you. And just like you'd be able to
provide any implementation as @getCurrentTime@ and @log@ parameters you can do the same with
simple effects.
.
> myFunction
> & implement (TimeMethods someCurrentTimeImplementation)
> & implement (LoggingMethods someLoggingImplementation)
.
=== Test effectful code
.
Easily provide dummy implementations of your effects to prevent missle-launching during testing.
.
> myEffectfulFunction :: MonadEffects '[Database, Missiles] m => m Int
>
> main = do
> conn <- connectToDb "connStr"
> myEffectfulFunction
> & implement (realDatabase conn)
> & implement (MissilesMethods (launchMissles "access codes"))
>
> spec = do
> res <- myEffectfulFunction
> & implement (fakeDb Map.empty)
> & implement (MissilesMethods (print "Totally launching missiles"))
> when (res /= 42) (error "Test failed!")
.
=== Avoid the \(n \times k\) instance problem
.
Any effect you define is automatically liftable through any transformer. Most @MonadX@ instances
you'd write would look like @func a b c = lift (func a b c)@, so why would you have to write them
yourself? @simple-effects@ does it for you using an overlappable instance.
.
What about effects that aren't that simple? Each effect can specify a constraint on the transformers
that it can be lifted through and a mechanism that does the lifting. So you get all the benefits
of automatic lifting of simple effects and retain all of the flexibility of complex ones.
.
=== Define custom effects with very little programming overhead
.
Lets say we need a way to get coordinates for some address. Here's how we'd declare that
functionality.
.
@
data Geolocation m = GeolocationMethods
  { _getLocation :: Address -> m Coordinates }
  deriving (Generic, Effect)
getLocation :: MonadEffect Geolocation m => Address -> m Coordinates
getLocation = _getLocation effect
@
.
That's all you need to start using your effect in functions.
.
> getUsersLocation :: (MonadEffect Geolocation m, MonadIO m) => m Coordinates
> getUsersLocation = do
> liftIO $ putStrLn "Please enter your address:"
> addr <- liftIO readLn
> getLocation addr
.
==== <Tutorial-T1_Introduction.html Check out the tutorial modules for more details>
.
homepage: https://gitlab.com/LukaHorvat/simple-effects
license: BSD3
license-file: LICENSE
author: Luka Horvat
maintainer: luka.horvat9@gmail.com
copyright: 2018 Luka Horvat
category: Control
build-type: Simple
cabal-version: >=1.10
extra-source-files: CHANGELOG.md
library
exposed-modules: Control.Effects
, Control.Effects.State
, Control.Effects.Reader
, Control.Effects.List
, Control.Effects.Signal
, Control.Effects.Early
, Control.Effects.Generic
, Control.Effects.Async
, Control.Effects.Yield
, Control.Effects.Resource
, Control.Effects.Newtype
, Control.Monad.Runnable
, Tutorial.T1_Introduction
, Tutorial.T2_Details
, Tutorial.T3_CustomEffects
other-modules: Import
Tutorial.Test
hs-source-dirs: src
default-language: Haskell2010
build-depends: base >= 4.7 && < 5
, transformers
, mtl
, monad-control == 1.0.*
, transformers-base == 0.4.*
, list-t
, array
, MonadRandom
, exceptions
, text
, bytestring
, async
ghc-options: -Wall -O2
test-suite tests
hs-source-dirs: test
main-is: Main.hs
default-language: Haskell2010
type: exitcode-stdio-1.0
build-depends: base >= 4.7 && < 5
, simple-effects
ghc-options: -Wall -threaded -with-rtsopts=-N
benchmark bench-effects
type: exitcode-stdio-1.0
hs-source-dirs: bench
main-is: Bench.hs
build-depends: base
, criterion
, mtl
, transformers
, simple-effects
default-language: Haskell2010
ghc-options: -O2