现在,node.js支持ECMAScript
Harmony生成器,
我们可以do
在Haskell中简洁地编写ala代码单子代码了:
function monad(unit, bind) {
return function (f) {
return function () {
var g = f.apply(this, arguments);
return typeOf(g) === "Generator" ? send() : unit(g);
function send(value) {
var result = g.next(value);
if (result.done) return unit(result.value);
else return bind(result.value, send);
}
};
};
}
function typeOf(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
在上面的代码中,monad
有一个函数可用于创建 确定性 单子,例如:
var maybe = monad(function (a) {
return {just: a};
}, function (m, f) {
return m === null ? null : f(m.just);
});
您现在可以maybe
按以下方式使用:
var readZip = maybe(function * (a, b) {
var a = yield readList(a);
var b = yield readList(b);
return _.zip(a, b);
});
上面的函数readZip
接受两个字符串,将它们转换为列表,然后压缩它们。如果有错误,则立即返回null
。它取决于以下功能:
function readList(string) {
try {
var value = JSON.parse(string);
return value instanceof Array ? {just: value} : null;
} catch (error) {
return null;
}
}
我们对其进行测试,以检查其是否可以正常工作:
console.log(readZip('[1,2,3,4]', '["a","b"]')); // [[1,"a"],[2,"b"],[3,"c"]]
console.log(readZip('hello', '["a","b"]')); // null
console.log(readZip('[1,2,3,4]', 'world')); // null
同样,我们可以创建任何其他确定性单子。例如,我最喜欢的cont
monad:
var cont = monad(function (a) {
return function (k) {
return k(a);
};
}, function (m, k) {
return function (c) {
return m(function (a) {
return k(a)(c);
});
};
});
现在,我们可以使用cont
简洁地创建连续传递样式的函数:
var fib = cont(function * (n) {
switch (n) {
case 0: return 0;
case 1: return 1;
default:
var x = yield fib(n - 1);
var y = yield fib(n - 2);
return x + y;
}
});
您可以使用以下fib
功能:
fib(10)(function (a) { console.log(a); }); // 55
不幸的是,monad
仅适用于确定性单子。它不适用于像list
monad 这样的不确定的monad,因为您只能从特定位置恢复一次生成器。
所以我的问题是:还有其他方法可以list
在JavaScript中简洁地实现非确定性monad吗?
所以我的问题是:还有其他方法可以
list
在JavaScript中简洁地实现非确定性monad吗?
是的,您可以使用生成器àla
immutagen在JavaScript中简洁地实现非确定性monad,例如list
monad 。但是,由于无法多次从特定位置恢复JavaScript中的生成器,因此您必须通过创建和重放多个生成器来模仿此行为。该解决方案具有几个缺点。
创建非确定性单子(例如列表单子)所需要的是不可变的生成器。不变生成器可以从特定位置多次恢复。不幸的是,JavaScript本身并不支持不可变的生成器。但是,我们可以通过创建和重放多个可变生成器来模拟它。因此,让我们看一下如何创建不可变的生成器。
我们需要解决的第一个问题是将可变生成器重播到特定点的方法。我们使用称为再生器的特殊功能类来实现。再生器是返回可变生成器的任何函数。此类函数的最简单示例是function* () {}
。因此,每个生成器功能都是一个再生器,但不是每个再生器都是一个生成器功能。您可以使用以下功能通过推进旧的再生器来创建新的再生器。
// type Regenerator = Arguments -> MutableGenerator
// next :: (Regenerator, Arguments) -> Regenerator
const 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 ignored
const regen3 = next(regen2, 10);
const gen1 = regen3(20);
const gen2 = regen3(30);
const result1 = gen1.next(40).value; // 10 + 20 + 40
const result2 = gen2.next(50).value; // 10 + 30 + 50
console.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 -> ImmutableGenerator
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));
该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 + 30
const result2 = bar.next(40).value; // 10 + 20 + 40
console.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
。
本文向大家介绍如何在JavaScript中实现多态?,包括了如何在JavaScript中实现多态?的使用技巧和注意事项,需要的朋友参考一下 多态性 多态 是面向对象编程(OOP)的宗旨之一。它有助于设计对象,使其可以与特定提供的对象共享或覆盖任何行为。多态性 利用继承的 优势来实现这一点。 在以下示例中,子对象(例如“板球”和“网球”)已覆盖从父对象“游戏”调用的“选择”方法,并分别返回了新字符串
问题内容: JavaScript 函数使用哪种算法?我知道它可以采用各种参数和函数来执行不同种类的排序,我只是对香草排序使用哪种算法感兴趣。 问题答案: 如果查看此错误224128,则看来Mozilla正在使用MergeSort。
问题内容: 是否有 JavaScript jvm实现 ? 如果没有,您能给我一些为什么它还没有意识到的原因吗?(可能不可能吗?)我试图了解创建一个缺少什么? 我问的原因是我想创建具有编译功能的Web浏览器ide,而无需在计算机上安装jdk或jre(仅在浏览器中)。 问题答案: 不确定jsJVM的成熟程度如何,但是您可能会对您感兴趣的东西看起来很像。如页面所示,它是用Javascript编写的JVM
虽然 JavaScript 和 ECMAScript 通常都被人们用来表达相同的含义,但 JavaScript 的含义却比 ECMA-262 中规定的要多得多。没错,一个完整的 JavaScript 实现应该由下列三个不同的部分组成(见图 1-1)。 核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模型(BOM) 1.2.1 ECMAScript 由 ECMA-262 定义的 EC
问题内容: 那里有许多MD5 JavaScript实现。有人知道哪一个是最先进,最错误修正和最快的吗? 我需要这个工具。 问题答案: 我建议您在这种情况下使用CryptoJS。 基本上,CryptoJS是使用最佳实践和模式在JavaScript中实现的标准安全加密算法的不断增长的集合。它们速度很快,并且具有一致且简单的界面。 因此,如果要计算密码字符串的MD5哈希,请执行以下操作: 因此,此脚本会
问题内容: 在JavaScript中实现堆栈和队列的最佳方法是什么? 我正在寻找shunting-yard算法,并且我将需要这些数据结构。 问题答案: var stack = []; stack.push(2); // stack is now [2] stack.push(5); // stack is now [2, 5] var i = stack.pop(); // stack is no