Either Monad:如何收集所有正确的值并在最后处理所有这些值?

Either Monad: How to collect all the Right values and do work with all of them at the end?

所以我想做的是从一系列 Either 结果中收集所有正确的值,并在链的末端提供所有这些值以对它们进行处理。如果 Either 值之一是 Left,我还希望链快速失败。

所以在阅读之后我相信让这一切工作的关键是柯里化函数和应用仿函数的组合。

下面是我目前使用的示例代码,它还不能正常工作。请注意,我使用的是 monet.js 和 lodash:

const test1 = Right('test1');
const test2 = Left('test2');
const test3 = Right('test3');

function success(val, val2, val3){
    return {
        val, val2, val3
    };
}

const curriedFn = _.curry(success);

Right(curriedFn)
    .ap(Right(function(fn){
        return fn(test1);
    }))
    .ap(Right(function(fn){
        return fn(test1);
    }))
    .ap(Right(function(fn){
        return fn(test1);
    }))
    .map(function(res){
        console.log(res);
    });

最后我得到一个包含 3 个 Either 值的对象,如下所示:

{ val: { isRightValue: true, value: 'test1' },
  val2: { isRightValue: true, value: 'test1' },
  val3: { isRightValue: true, value: 'test1' } }

我要的是3个实际值。如果您看到,Either 值之一是 Left,链条应该已经断开。

我正在尝试以一种纯函数式的方式来做到这一点。这就是为什么我不在函数范围之外的对象中映射和填充值的原因。

有什么想法吗?备选方案?

您似乎使用 .ap 不正确

const Either =
  require ('data.either')

const { Left, Right } =
  Either

const success = x => y => z =>
  [ x, y, z ]

const a =
  Right (1)

const b =
  Right (2)

const c =
  Right (3)

const badegg =
  Left ('badegg')

如果将 success 应用于任何参数的 badegg,则直接结果将是 Left。对 .ap 的后续调用不会影响 Left

Right (success)
  .ap (a)
  .ap (b)
  .ap (c)
  .fold (console.error, console.log) // [ 1, 2, 3 ]

Right (success)
  .ap (badegg)
  .ap (b)
  .ap (c)
  .fold (console.error, console.log) // "badegg"

Right (success)
  .ap (a)
  .ap (badegg)
  .ap (c)
  .fold (console.error, console.log) // "badegg"

Right (success)
  .ap (a)
  .ap (b)
  .ap (badegg)
  .fold (console.error, console.log) // "badegg"

所以我误读了文档:https://monet.github.io/monet.js/#maybe

您需要嵌套连续的 .ap 调用。下面是我在上面尝试做的重做示例:

const test1 = Right('test1');
const test2 = Right('test2');
const test3 = Right('test3');

const success = _.curry(function (val, val2, val3){
    return {
        val,
        val2,
        val3
    };
});

test3.ap(test2.ap(test1.map(success)))
    .map(success => {
        console.log(success)
    });

我确信 compose 或其他一些 monad 有一种优雅的方式来展平链条,但目前我很满意。