How to transfer Either.Right to Either.Left?

171 views Asked by At
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?

1

There are 1 answers

0
Scott Christopher On BEST ANSWER

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)
));