在JavaScript中实现monad

在JavaScript中实现monad,第1张

在JavaScript中实现monad

所以我的问题是:还有其他方法可以

list
在Javascript中简洁地实现非确定性monad吗?

是的,您可以使用生成器àla
immutagen在Javascript中简洁地实现非确定性monad,例如list
monad 。但是,由于无法多次从特定位置恢复Javascript中的生成器,因此您必须通过创建和重放多个生成器来模仿此行为。该解决方案具有几个缺点。

  1. 它的效率很低,因为需要创建并重播多个生成器,从而导致时间复杂度呈二次增长。
  2. 它仅适用于纯monad和纯计算,因为需要创建并重播多个生成器。因此,副作用将被错误地多次执行。

创建非确定性单子(例如列表单子)所需要的是不可变的生成器。不变生成器可以从特定位置多次恢复。不幸的是,Javascript本身并不支持不可变的生成器。但是,我们可以通过创建和重放多个可变生成器来模拟它。因此,让我们看一下如何创建不可变的生成器。

我们需要解决的第一个问题是将可变生成器重播到特定点的方法。我们使用称为再生器的特殊功能类来实现。再生器是返回可变生成器的任何函数。此类函数的最简单示例是

function*() {}
。因此,每个生成器功能都是一个再生器,但不是每个再生器都是一个生成器功能。您可以使用以下功能通过推进旧的再生器来创建新的再生器。

// type Regenerator = Arguments -> MutableGenerator// next :: (Regenerator, Arguments) -> Regeneratorconst next = (regen, ...args) => data => {    const gen = regen(...args);    return gen.next(data), gen;};

next
功能可用于将再生器推进到特定点。例如,考虑以下代码片段。

const next = (regen, ...args) => data => {    const gen = regen(...args);    return gen.next(data), gen;};const regen1  = next(regen0, 1, 2, 3);const regen2  = next(regen1, undefined); // first value of mutable generator ignoredconst regen3  = next(regen2, 10);const gen1 = regen3(20);const gen2 = regen3(30);const result1 = gen1.next(40).value; // 10 + 20 + 40const result2 = gen2.next(50).value; // 10 + 30 + 50console.log(result1, result2);function* regen0(a, b, c) {    const x = yield a;    const y = yield b;    const z = yield c;    return x + y + z;}

如您所见,我们可以使用该

next
函数推进再生器,或者将再生器应用于值以获得可变的生成器。现在,我们可以将可变的生成器重播到特定的位置,我们可以如下创建不可变的生成器。

// immutagen :: Regenerator -> Arguments -> ImmutableGeneratorconst immutagen = regen => (...args) => function loop(regen) {    return (gen, data) => {        const {value, done} = gen.next(data);        if (done) return {value, next: null};        let replay = false;        const recur = loop(next(regen, data));        return {value, next: value => { if (replay) return recur(regen(data), value); replay = true; return recur(gen, value);        }};    };}(next(regen, ...args))(regen(...args));

immutagen
函数可用于创建不可变的生成器函数,我们可以称其为产生不可变的生成器。以下是有关如何创建和使用不可变生成器的示例。

const next = (regen, ...args) => data => {    const gen = regen(...args);    return gen.next(data), gen;};const immutagen = regen => (...args) => function loop(regen) {    return (gen, data) => {        const {value, done} = gen.next(data);        if (done) return {value, next: null};        let replay = false;        const recur = loop(next(regen, data));        return {value, next: value => { if (replay) return recur(regen(data), value); replay = true; return recur(gen, value);        }};    };}(next(regen, ...args))(regen(...args));const foo = immutagen(function* (a, b, c) {    const x = yield a;    const y = yield b;    const z = yield c;    return x + y + z;});const bar = foo(1, 2, 3).next(10).next(20);const result1 = bar.next(30).value; // 10 + 20 + 30const result2 = bar.next(40).value; // 10 + 20 + 40console.log(result1, result2);

最后,现在我们有了不可变的生成器,我们可以更简洁地实现非确定性单子,例如列表单子,如下所示:

const next = (regen, ...args) => data => {    const gen = regen(...args);    return gen.next(data), gen;};const immutagen = regen => (...args) => function loop(regen) {    return (gen, data) => {        const {value, done} = gen.next(data);        if (done) return {value, next: null};        let replay = false;        const recur = loop(next(regen, data));        return {value, next: value => { if (replay) return recur(regen(data), value); replay = true; return recur(gen, value);        }};    };}(next(regen, ...args))(regen(...args));const monad = bind => regen => (...args) => function loop({value, next}) {    return next ? bind(value, val => loop(next(val))) : value;}(immutagen(regen)(...args));const flatMap = (array, callback) => array.flatMap(callback);const list = monad(flatMap);const foo = list(function* (xs, ys) {    const x = yield xs;    const y = yield ys;    return [x * y];});console.log(foo([1, 2, 3], [4, 5, 6]));

请注意,该

monad
功能仅需要
bind
。不需要了
unit



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5172588.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-18
下一篇 2022-11-18

发表评论

登录后才能评论

评论列表(0条)

保存