Monad:如何收集所有正确的价值观并最终与所有这些价值观合作?

时间:2018-03-08 17:30:50

标签: functional-programming monads either monetjs

所以我要做的是从一系列Either结果中收集所有Right值,并在链的末尾使用它们来完成它们的工作。如果其中一个Either值是Left,我也希望链快速失败。

因此,在阅读之后,我相信让这一切全部发挥作用的关键是一个curried函数和一个applicative functor的组合。

下面是我到目前为止的示例代码,但它并不是很有用。请注意,我使用的是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个值的对象,如下所示:

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

我想要的是3个实际值。如果你看到,其中一个Either值是Left,链条应该被打破。

我试图以纯粹的功能方式做到这一点。这就是为什么我没有在函数范围之外的对象中映射和填充值。

有什么想法吗?替代?

2 个答案:

答案 0 :(得分:1)

您似乎错误地使用了.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"

答案 1 :(得分:1)

所以我误读了文档: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有一种优雅的方式可以将链条弄平,但暂时我很满意。