【发布时间】:2021-02-01 08:38:44
【问题描述】:
我知道如何实现单链表 monad 转换器,但无法运行其对应的数组。问题是存在分组效应,使得变压器只对可交换的基本单子有效。下面是一个例子,为了简单起见,transformer 和 base monad 都是数组,并且没有transformer 类型的包装器:
// ARRAY
const arrMap = f => xs =>
xs.map((x, i) => f(x, i));
const arrAp = tf => xs =>
arrFold(acc => f =>
arrAppend(acc)
(arrMap(x => f(x)) (xs)))
([])
(tf);
const arrOf = x => [x];
const arrChain = mx => fm =>
arrFold(acc => x =>
arrAppend(acc) (fm(x))) ([]) (mx);
// Transformer
const arrChainT = ({map, ap, of ,chain}) => mmx => fmm =>
chain(mmx) (mx => {
const go = ([x, ...xs]) =>
x === undefined
? of([])
: ap(map(arrCons) (fmm(x))) (go(xs));
return chain(go(mx)) (ys => of(arrFold(arrAppend) ([]) (ys)));
});
const arrOfT = of => x => of([x]);
// Transformer stack
const arrArrChain = arrChainT(
{map: arrMap, ap: arrAp, of: arrOf, chain: arrChain});
const arrArrOf = arrOfT(arrOf);
// auxiliary functions
const arrFold = f => init => xs => {
let acc = init;
for (let i = 0; i < xs.length; i++)
acc = f(acc) (xs[i], i);
return acc;
};
const arrAppend = xs => ys =>
xs.concat(ys);
const arrCons = x => xs =>
[x].concat(xs);
// MAIN
foo = x =>
x === 0
? [[0, 1]]
: [[0], [1]];
console.log(JSON.stringify(
arrArrChain(arrArrChain(foo(0)) (foo)) (foo)));
// yields [[0,1,0,0,1],[0,1,1,0,1],[0,1,0,0],[0,1,0,1],[0,1,1,0],[0,1,1,1]]
console.log(JSON.stringify(
arrArrChain(foo(0)) (x => arrArrChain(foo(x)) (foo))));
// yields [[0,1,0,0,1],[0,1,0,0],[0,1,0,1],[0,1,1,0,1],[0,1,1,0],[0,1,1,1]]
两种计算都应该产生相同的结果。现在我的问题是:有没有办法以合法的方式实现数组转换器?
【问题讨论】:
-
数组的 monad 转换器实例将是 same as that of lists,因为它们是同构的。请注意,列表 monad 转换器实例的 naive implementation 也不会产生 monad,除非参数 monad 是可交换的。
-
@AaditMShah 我把 Listt-done-right 严格了,它仍然有效。我不想承认,但毕竟你是对的。
标签: javascript functional-programming monads monad-transformers