0
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?

Cactus
  • 27,075
  • 9
  • 69
  • 149
qwang07
  • 1,136
  • 2
  • 11
  • 20

1 Answers1

2

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)
));
Scott Christopher
  • 6,458
  • 23
  • 26