如何将Either.Right转移到Either.Left?

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

如果第一个测试没有通过,它将return Either.Left,第二个不会被调用。它将输出:

_Right {value: user}

但是如果第一个通过而第二个没有通过,那么就会变成:

_Right {value: _Left {value: err}}

我要它只输出_Left {value: err},请问如何修改代码或者有什么方法可以将右移到左?

您注意到 map 无法 "flatten" 两个 Either 实例在一起。为此,您需要使用 chain

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

这种将一系列调用组合在一起的模式也可以通过 composeK/pipeK 实现,其中每个要组合的函数必须采用 Monad m => a -> m b 的形式,即一个函数产生一些来自给定值的 monad(例如 Either)。

使用 R.pipeK,您的示例可以修改为:

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