这是Javascript中有效的monad转换器吗?

时间:2016-09-20 15:24:27

标签: javascript functional-programming monads monad-transformers

为了更好地理解monad变换器,我实现了一个。由于Javascript是动态类型的,我不是模仿类型或数据构造函数,而是仅声明普通的旧Javascript对象,它们保存相应的静态函数以形成特定的monad / transformer。基本思想是将这些方法应用于容器类型中的值/值。类型和容器是分开的,可以这么说。

Array s可以包含任意数量的元素。扩展Array以便它们实现monad接口是微不足道的。 Array也可以代表maybe类型的两种变体。空Array对应nothing。具有单个元素的Array对应于just(a)。因此,我将使用Array s作为我的容器类型。请注意,这是一个快速而肮脏的实现,仅用于学习:

const array = {
  of: x => Array.of(x),
  map: f => ftor => ftor.map(f),
  ap: ftor => gtor => array.flatten(array.map(f => array.map(f) (gtor)) (ftor)),
  flatten: ftor => ftor.reduce((xs, y) => xs.concat(y), []),
  chain: mf => ftor => array.flatten(array.map(mf) (ftor))
}

const maybe = {
  of: array.of,
  empty: () => [],
  throw: ftor => { if (ftor.length > 1) throw Error("indeterministic value"); return ftor },
  map: f => ftor => maybe.throw(ftor).map(f),
  ap: ftor => gtor => maybe.flatten(maybe.map(f => maybe.map(f) (gtor)) (ftor)),
  flatten: array.flatten,
  chain: mf => ftor => maybe.flatten(maybe.map(mf) (ftor)),
  T: M => {
    return {
      of: x => M.of(maybe.of(x)),
      empty: () => M.of(maybe.empty()),
      map: f => ftor => M.map(gtor => maybe.map(f) (gtor)) (ftor),
      ap: ftor => gtor => M.flatten(M.map(htor => M.map(itor => maybe.ap(htor) (itor)) (gtor)) (ftor)),
      flatten: maybe.flatten,
      chain: mf => ftor => M.chain(gtor => maybe.chain(mf) (gtor)) (ftor)
    };
  }
};

现在我将一个可能的变换器与monadic数组合并,以获得一个可以处理arraymaybe s的monad。

const arraym = maybe.T(array);

const add = x => y => x + y;
const addm = x => y => [x + y];
const arrayOfMaybes = [[1],[],[3]]

当我将arraym视为一个应用函子时,一切都按预期工作:

// yields: [[11],[],[13]] as expected
arraym.ap(arraym.map(add) (arrayOfMaybes)) (arraym.of(10));

然而,当我申请chain时出现问题:

// yields: [11,13] but [[11],[13]] expected
arraym.chain(x => arraym.chain(y => addm(x) (y)) (arrayOfMaybes)) ([[10]])

是这个问题的原因

  • 这不是一个有效的monad变压器吗?
  • 我申请连锁的方式是错的?
  • 我对结果的期望是错误的?

1 个答案:

答案 0 :(得分:1)

  

这个问题的原因是我应用链的方式是错误的吗?

是。您需要传递返回mf的{​​{1}},而不是像arraym那样的array。你可以用

addm

为了解决这个问题,您还可以考虑为每个monad变换器实现lift