I have successfully implemented the single linked list monad transformer, however, I am struggling to get its array counterpart functioning properly. The issue stems from a grouping effect that restricts the transformer's validity to commutative base monads only. To illustrate this problem, both the transformer and base monad are arrays in the following example without any type wrapper:
// 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]]
Both scenarios should produce the same outcome. Hence, my question stands: Is there a way to implement the array transformer in a lawful manner?