Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add local function to Reader and ReaderT #505

Open
svozza opened this issue Jan 18, 2021 · 0 comments
Open

Add local function to Reader and ReaderT #505

svozza opened this issue Jan 18, 2021 · 0 comments

Comments

@svozza
Copy link

svozza commented Jan 18, 2021

Is your feature request related to a problem? Please describe.
In Haskell the Reader monad has a function called local that let's you to temporarily modify the environment used by the monad. This is really useful when you want to pass the results of a previous call to functions later on in the computation.

Describe the solution you'd like
I would like to Crocks to implement the local function as per Haskell. Interesting this just appears to be contramap but the Haskell implementation is still called local for some reason. I am happy to work on a PR for this if there's an appetite to add this function.

Describe alternatives for how you do this now
I toyed with the idea of nesting ReaderT monads but this solution is much cleaner

Code
I don't have a REPL but have already got this working locally and it was very easy (I basically just translated from Haskell).

// Reader

  function local(method) {
    return function(fn) {
      if(!isFunction(fn)) {
        throw new TypeError(("Reader." + method + ": Function required"))
      }

      return Reader(e => runWith(fn(e)))
    }
  }

// ReaderT

    function local(fn) {
      if(!isFunction(fn)) {
        throw new TypeError(((type()) + ".map: Function required"))
      }

      return ReaderT(function (e) { return runWith(fn(e)) })
    }

To use it's very simple.

const {Async, ReaderT} = require('crocks');

const ReaderAsync = ReaderT(Async);

// localFunc :: String -> ReaderT e (Async a b)
function localFunc(paramToAdd) {
  return func1() // returns a ReaderAsync 
    .chain(func2) // function requires paramToAdd to be in env
    .chain(func3) // function requires paramToAdd to be in env
    .local(e => ({y: paramToAdd, ...e}) // previous 3 functions will use modified env
    .map(func4) // will use unmodified env
}

getParamToAdd()
.chain(localFunc)
.map(func5)
// ...
.runWith({x: 'param'})
.fork(/* ... */)

Here's some real code that uses this new function if you want something more interesting than the above contrived example:

https://github.com/svozza/functionalish-refactor/blob/master/functional/lib/index.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant