qwang qwang - 1 year ago 40
Javascript Question

How to transfer Either.Right to Either.Left?

db.findUser(id).then(R.pipe(
R.ifElse(firstTestHere, Either.Right, () => Either.Left(err)),
R.map(R.ifElse(secondTestHere, obj => obj, () => Either.Left(err))),
console.log
))


If the first test doesn't pass, it will return Either.Left, and the second one won't be called. It will out put:

_Right {value: user}


But if the first one passed but the second one doesn't, it will become:

_Right {value: _Left {value: err}}


I want it to output _Left {value: err} only, how to fix the code or is there any way to transfer the Right to the Left?

Answer Source

What you've noticed there is that map is unable to "flatten" the two Either instances together. To do that, you will want to use chain instead.

db.findUser(id).then(R.pipe(
  R.ifElse(firstTestHere, Either.Right, () => Either.Left(err)),
  R.chain(R.ifElse(secondTestHere, Either.Right, () => Either.Left(err))),
  console.log
))

This pattern of composing series of calls to chain together can also be achieved with composeK/pipeK, where each function that is to be composed must take the form Monad m => a -> m b, i.e. a function that produces some monad (such as Either) from a given value.

Using R.pipeK, your example could be modified to something like:

// helper function to wrap up the `ifElse` logic
const assertThat = (predicate, error) =>
  R.ifElse(predicate, Either.Right, _ => Either.Left(error))

const result = db.findUser(id).then(R.pipeK(
  assertThat(firstTestHere, err),
  assertThat(secondTestHere, err)
));
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download