Skip to content

Add local function to Reader and ReaderT #505

@svozza

Description

@svozza

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions