packages feed

has-transformers 0.1.0.1 → 0.1.0.2

raw patch · 4 files changed

+31/−16 lines, 4 files

Files

CHANGELOG.md view
@@ -7,3 +7,7 @@ ## 0.1.0.1 -- 2021-12-05  * Added readme to hackage++## 0.1.0.2 -- 2021-12-05++* Improved readme
README.md view
@@ -8,12 +8,13 @@ ### What exactly?  Given a transformer stack `t1 (t2 (t3 (... m))) a`,-you can automatically lift any function `thing :: tN m a` into the stack with a single function, `liftH`.+you can automatically lift any function `thing :: tN m a` into the stack with a single function,+[`liftH`](https://hackage.haskell.org/package/has-transformers/docs/Control-Monad-Trans-Has.html#v:liftH).  ### What features does it have?  * _Final encoding_:-  There is a type class `Has t m` that says that the transformer `t` is in the stack `m`.+  There is a type class [`Has t m`](https://hackage.haskell.org/package/has-transformers/docs/Control-Monad-Trans-Has.html#t:Has) that says that the transformer `t` is in the stack `m`. * _Extensibility_:   Standard [`transformers`](https://hackage.haskell.org/package/transformers/) are supported out of the box.   You can add any further transformers to your stack.@@ -50,7 +51,7 @@ separate concerns, invert dependencies, have clean architecture, and be able to change your monad stack without breaking existing code? -Then simply use the `Has` typeclass,+Then simply use the [`Has`](https://hackage.haskell.org/package/has-transformers/docs/Control-Monad-Trans-Has.html#t:Has) typeclass, and replace all your `lift` orgies with its one function, `liftH`.  But isn't this a solved problem, you ask?@@ -63,6 +64,11 @@ The usual advantage is that `has-transformers` is fast and simple, and the disadvantage is that it doesn't have higher order effects. +There is a big design space here,+and maybe there is no ideal library for every use case.+While some corners of the space have been explored thoroughly,+there is this neat little corner that hasn't received as much attention as maybe deserved.+ #### `mtl`  Historically, `mtl` solves the same problem like `has-transformers`,@@ -124,7 +130,7 @@ because there is no runtime overhead associated to effect handling. (Although the overhead is expected to be small in `eff` when/if delimited continuations are merged in GHC.) How big this overhead is, I can't judge, but it's probably smaller than you'll care about in production.-Also see https://github.com/fused-effects/fused-effects#benchmarks and https://github.com/polysemy-research/polysemy#what-about-performance-tldr.+Also see [the `fused-effects` benchmarks](https://github.com/fused-effects/fused-effects#benchmarks) and [a `polysemy` performance discussion](https://github.com/polysemy-research/polysemy#what-about-performance-tldr).  On the other hand, all these libraries support higher-order effects. (`operational` is not really extensible out of the box.@@ -157,11 +163,11 @@ #### Can you please give us a feature matrix?  | Library | Extensible | Higher order effects | "Fusion" / no runtime interpretation | Arbitrary base monads |-| --- | --- | --- | --- |+| --- | --- | --- | --- | --- | | [`has-transformers`](https://www.github.com/turion/has-transformers/) | ✅ | ❌ | ✅ | ✅ | | [`mtl`](https://hackage.haskell.org/package/mtl) | ❌ | ✅ | ✅ | ✅ |-| [`fused-effects`](https://hackage.haskell.org/package/fused-effects) | ✅ | ✅ | ✅ |-| [`polysemy`](https://hackage.haskell.org/package/polysemy), [`freer-simple`](https://hackage.haskell.org/package/freer-simple), ... | ✅ | ❌ | ✅ |+| [`fused-effects`](https://hackage.haskell.org/package/fused-effects) | ✅ | ✅ | ✅ | ✅ |+| [`polysemy`](https://hackage.haskell.org/package/polysemy), [`freer-simple`](https://hackage.haskell.org/package/freer-simple), ... | ✅ | ❌ | ✅ | ✅ | | [`rio`](https://hackage.haskell.org/package/rio) | ✅ | ❌ | ✅ | ❌ |  Let me know if other features & libraries are important to you.@@ -197,6 +203,15 @@ (which somewhat defeats the purpose of an effect library), or use another library to address these effects. +### So what's your recommendation on effect systems?++My opinionated, limited-point-of-view recommendation,+without knowing your use case,+is that you should use `transformers` and give `has-transformers` a try if you have a small project that doesn't do anything too fancyful with effects,+and when you hit stuff like complex error handling, backtracking, and so on,+upgrade to `fused-effects` if you don't get a headache with the types,+or migrate to `polysemy` (or maybe `freer-simple`) otherwise.+ ## How?  The central insight is that a transformer `t` is not only an effect handler,@@ -227,14 +242,14 @@  ### Can I use two `ReaderT`, two `StateT`, etc., in the same stack? -Yes. See the [`TwoReaders`](https://www.github.com/turion/has-transformers/examples/Examples/TwoReaders.hs) example.+Yes. See the [`TwoReaders`](https://github.com/turion/has-transformers/blob/master/examples/Examples/TwoReaders.hs) example. You might have to add some type signatures here and there to help GHC figure it out.  ### Does this work with _any_ transformer?  Most transformers. [`ContT`](https://hackage.haskell.org/package/transformers/docs/Control-Monad-Trans-Cont.html#t:ContT)-(and other continuation based transformers like [`LogicT](https://hackage.haskell.org/package/logict/docs/Control-Monad-Logic.html#t:LogicT))+(and other continuation based transformers like [`LogicT`](https://hackage.haskell.org/package/logict/docs/Control-Monad-Logic.html#t:LogicT)) don't work, but any transformer that is strictly positive in its monad works (i.e., `ReaderT`, `WriterT`, `StateT`, `ExceptT`, `AccumT`, and so on).
has-transformers.cabal view
@@ -1,8 +1,8 @@ cabal-version:      2.4 name:               has-transformers-version:            0.1.0.1+version:            0.1.0.2 -synopsis: This library `Has` transformers+synopsis: This library 'Has' transformers  description:   A very slim library for first-order effects based on monad transformers
src/Control/Monad/Trans/Has.hs view
@@ -4,10 +4,6 @@  import "transformers" Control.Monad.Trans.Class --- |--- class Has t m where---   liftH :: t Identity a -> m a- {- | The transformer stack @m@ contains the transformer @t@.  Explicitly, @m = t1 (t2 (t3 ... (tN m)...))@,@@ -18,7 +14,7 @@    This will apply 'lift' as many times as necessary to insert the action.   The higher-rank type involving @forall n@ basically says:-  "The action to lift must only use the structure of the _transformer_,+  "The action to lift must only use the structure of the /transformer/,   not of a specific monad,   and is thus definable for any monad @n@".   -}