packages feed

moo-nad 0.1.0.1 → 0.1.0.2

raw patch · 2 files changed

+96/−3 lines, 2 filesdep ~base

Dependency ranges changed: base

Files

+ README.md view
@@ -0,0 +1,89 @@+# moo-nad++In [this Stack Overflow+question](https://stackoverflow.com/questions/61642492/simplifying-the-invocation-of-functions-stored-inside-an-readert-environment),+I asked how to simplify the invocation of functions stored in a `ReaderT`+environment.++For example, when invoking a `Int -> String -> _ ()` logging function from the environment, I would+like to simply be able to write:++    logic :: ReaderT EnvWithLogger IO ()+    logic = do+        self logger 7 "this is a message"++instead of something like++    logic :: ReaderT EnvWithLogger IO ()+    logic = do+        e <- ask+        liftIO $ logger e 7 "this is a message"++(Yes, I'm aware that this isn't *that* big of a hassle, and that solving it might+overcomplicate other things. But bear with me.)++The question received [this+answer](https://stackoverflow.com/a/61642757/1364288), which worked like a+charm. The answer also included the following comment:++> Implementing variadics with type classes is generally frowned upon because of+> how fragile they are, but it works well here because the RIO type provides a+> natural base case++That got me thinking: is there a way to avoid tying the workings of the+helper typeclass to a *concrete* monad, like+[`RIO`](http://hackage.haskell.org/package/rio)? Can the call-helper code be+made to work with a variety of reader-like monads?++After [a number of failed attempts](https://github.com/danidiaz/dep-t/issues/1)+using a typeclass-only approach, I turned to the solution explored in the+current repo: *abstract the monad and the environment using a [module+signature](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/separate_compilation.html#module-signatures)*.++That signature is called [`Moo`](./lib/Moo.hsig), and the module [`Moo.Prelude`](./lib/Moo/Prelude.hs) provides the+`self` and `call` helper methods.++## How to use this library to write program logic that is polymorphic on the monad and the environment?++This is an alternative to the usual way of abstracting the monad using [mtl](http://hackage.haskell.org/package/mtl).++Put program logic into indefinite libraries which depend+on the [`Moo` module signature](./lib/Moo.hsig). Import [`Moo.Prelude`](./lib/Moo/Prelude.hs) for the call helpers.++You'll likely need to expand the base `Moo` signature through [signature+merging](https://github.com/danidiaz/really-small-backpack-example/tree/master/lesson3-signature-merging) to require extra capabilities from the monad and/or the environment.++(**Note**: this approach is less fine-grained with respect to constraints than+the MTL one. When using MTL each individual function can have different+constraints. But here, functions from modules that import the same version of+`Moo` will share the same constraints. If you want constraint differentiation,+you'll need to create separate compilation units with different "enriched"+versions of `Moo`.)++You'll eventually need to write an implementation library that gives concrete instantiations for the monad and the environment.++In your executable, depend on both your program logic and the implementation library. The magic of [mixing matching](https://github.com/danidiaz/really-small-backpack-example/tree/master/lesson2-signatures) will take place, and you'll end up with a concrete version of your logic.++## Very well; how does an actual example look like?++- See the [example-logic-that-logs](./lib-example-logic-that-logs) internal library for an example of [abstract program logic](./lib-example-logic-that-logs/LogicThatLogs.hs) that imports an [enriched](./lib-example-logic-that-logs/Moo.hsig) version of `Moo`. ++- See also the [example-impl](./lib-example-impl) internal library that implements the `Moo` signature.++- The [test suite](./test/tests.hs) creates an actual concrete environment and runs the program logic with it.++Because we are using Backpack, we need to look at how everything is wired together+in the [cabal file](./moo-nad.cabal). Notice in particular how: ++- The program logic depends on `moo-nad` but *not* on the implementation.++- The implementation *doesn't* depend on `moo-nad`. Implementations in Backpack don't depend on the signatures they implement.++- The test suite depends on the program logic and the implementation.++## caveat emptor++At the end of the day, this method might involve too much ceremony to be practical. ++Feedback welcome. +
moo-nad.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               moo-nad-version:            0.1.0.1+version:            0.1.0.2  synopsis:           Invocation helpers for the ReaderT-record-of-functions style. description:@@ -31,11 +31,15 @@ license-file:       LICENSE author:             Daniel Diaz Carrete maintainer:         diaz_carrete@yahoo.com+category:           Control+extra-source-files: CHANGELOG.md, README.md -extra-source-files: CHANGELOG.md+source-repository    head+    type:     git+    location: https://github.com/danidiaz/moo-nad.git  common common-    build-depends:    base ^>= 4.15.0.0,+    build-depends:    base >= 4.11.0.0 && < 5,                       mtl  ^>= 2.2,                       dep-t ^>= 0.4.4     default-language: Haskell2010