simple-effects: A simple effect system that integrates with MTL
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.
Warnings:
- 'ghc-options: -O2' is rarely needed. Check that it is giving a real benefit and not just imposing longer compile times on your users.
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
Check out the tutorial modules for more details
Properties
Versions | 0.1.0.1, 0.1.0.2, 0.2.0.0, 0.2.0.1, 0.3.0.0, 0.3.0.1, 0.3.0.2, 0.4.0.0, 0.4.0.1, 0.5.0.0, 0.5.0.1, 0.5.0.2, 0.5.0.3, 0.6.0.0, 0.6.0.1, 0.6.0.2, 0.7.0.0, 0.7.0.1, 0.7.0.2, 0.8.0.2, 0.9.0.0, 0.9.0.1, 0.10.0.0, 0.10.0.1, 0.10.0.2, 0.11.0.0, 0.11.0.1, 0.12.0.0, 0.13.0.0, 0.13.0.0 |
---|---|
Change log | CHANGELOG.md |
Dependencies | array, async, base (>=4.7 && <5), bytestring, exceptions, ghc, ghc-tcplugins-extra, list-t, monad-control (>=1.0 && <1.1), MonadRandom, mtl, text, transformers, transformers-base (>=0.4 && <0.5) [details] |
License | BSD-3-Clause |
Copyright | 2018 Luka Horvat |
Author | Luka Horvat |
Maintainer | luka.horvat9@gmail.com |
Category | Control |
Home page | https://gitlab.com/LukaHorvat/simple-effects |
Uploaded | by darwin226 at 2018-12-18T22:26:44Z |
Modules
- Control
- Control.Effects
- Control.Effects.Async
- Control.Effects.Early
- Control.Effects.Generic
- Control.Effects.List
- Control.Effects.Newtype
- Control.Effects.Plugin
- Control.Effects.Reader
- Control.Effects.Resource
- Control.Effects.Signal
- Control.Effects.State
- Control.Effects.Yield
- Monad
- Control.Monad.Runnable
- Control.Effects
- Tutorial
- Tutorial.T1_Introduction
- Tutorial.T2_Details
- Tutorial.T3_CustomEffects
Downloads
- simple-effects-0.13.0.0.tar.gz [browse] (Cabal source package)
- Package description (as included in the package)
Maintainer's Corner
Package maintainers
For package maintainers and hackage trustees