3

I am trying to use Either Monad to pipe my data through, the problem is that I can't figure out how to make my Monad to be aware of the operation that is async

here is what I have

let processData = Either.either(_sendError, _sendResponse)

processData(_getDataGeneric(queryResult)
    .chain(_findDevice)
    .chain(_processRequest)
);

queryResult is what I fetch from the database itself.

the problem is that fetching the result is only in the middle of the pipeline. what I want is this

ValidateUserInput -> GetDataFromDB -> ProcessData

processAll(_fetchFromDB(userId)
    .getDataGeneric
    .chain(_findDevice)
    .chain(_processRequest))


//_fetchFromDB , Mongoose Query
 function _fetchFromDB(userId){
        return myModel.findOne({id:userId}).exec()
                                  .then(function(result){
                                     return Right(result)
                                }).catch((err)=>Left(err))
  }

if result is valid from DB,it will return an Right instance, and if there is any sort of error, it will return Left

the problem is that this operation is Async, and i am not sure how to get my Either Monad to handle it and process it.

Any ideas on how to make my Monad aware of Promises in its operation?

John
  • 488
  • 4
  • 19

1 Answers1

2

As you're seeing, an Either type can only represent values that have already been realised, while the asynchronous operation represents something that may be evaluated in the future.

A Promise already combines the behaviour of an Either, by representing the possibility of both error and successful values. It also captures the behaviour of monadic-style chaining of operations by allowing then to return another Promise instance.

If however you're interested in something similar to a Promise that behaves more closely to an Either (and also follows the Fantasy Land spec) then you might like to look at one of the Future implementations such as Fluture

e.g.

import Future from 'fluture';

const processAll = Future.fork(_sendError, _sendResponse);

const _fetchFromDB =
  Future.fromPromise(userId => myModel.findOne({ id: userId }).exec())

processAll(_fetchFromDB(userId)
  .chain(getDataGeneric)
  .chain(_findDevice)
  .chain(_processRequest))
Scott Christopher
  • 6,458
  • 23
  • 26
  • Ah I see! Thats what I suspected was happening. I understand the promises resemble very much the Either type, with reject(Left) and resolve(right) behaviour. What I really wanted to do was to consolidate Error handling. Eg, pass the Right side of a given promise into the right side of either chain, and process the given data. If there was a failure, I really care about the Catch part of the promise, and I wanted to make that apart of my error handling flow. Otherwise, I needed to handle the Either function pipeline, AND the promise.catch part of the error as well. is there a betterway? – John Dec 15 '16 at 02:39
  • It seems fluture can interface with the promise spec. Is there a way for me to use Future from ramda Fantasy land in the same way? – John Dec 15 '16 at 02:46
  • If you wanted to create a `fromPromise` function using Ramda Fantasy, it would look something like `fromPromise = fn => (...args) => Future((rej, res) => fn(...args).then(res, rej))` – Scott Christopher Dec 15 '16 at 11:53
  • For this fluture approach, how should null handling be implemented. I would imagine using Monad, but how would that fit in the code above? – user1790300 Mar 05 '21 at 16:34