【发布时间】:2017-02-08 23:52:52
【问题描述】:
我尝试在 Javascript 中实现 continuation monad 来处理 continuation 传递样式和异步控制流。这是我学习的延续单子:
// auxiliary functions
const log = prefix => x => console.log(prefix, x);
const addk = x => y => k => setTimeout((x, y) => k(x + y), 0, x, y);
const inck = x => k => setTimeout(x => k(x + 1), 0, x);
const sqr = x => x * x;
// continuation monad
const cont = {
of: x => k => k(x),
map: ftor => f => k => ftor(x => k(f(x))),
ap: ftor => gtor => k => ftor(x => gtor(f => k(f(x)))),
chain: ftor => mf => k => ftor(x => mf(x) (k)),
callcc: f => k => f(x => () => k(x)) (k)
};
// map a normal, unary function with an asynchronous function:
cont.map(inck(9)) (sqr) (log("map"));
// chain two asynchronous CPS computations with an asynchronous binary CPS function
const comp1 = cont.map(inck(4)) (sqr);
const comp2 = cont.map(inck(9)) (sqr);
cont.chain(comp1) (x => cont.chain(comp2) (y => addk(x) (y))) (log("chain"));
除了cont.ap,我没有发现他的好处,一切都很好。
现在我想模仿 Javascript 中同步控制流的throw/catch 机制。 callcc 似乎很合适,因为它提供了一种转义延续机制,可与延续单子一起使用,如http://hackage.haskell.org/ 所述。
但我不知道如何申请callcc,而且我还没有找到任何合适的来源来描述这样的申请。
【问题讨论】:
-
顺便说一句,强烈建议使用
R.curryN之类的东西,而不是手动柯里化所有函数 ramdajs.com/docs/#curryN -
@JaredSmith 这个问题没有 Rambda 标签。另外,您的推荐依据是什么?
-
@Jared 我反其道而行之:当我的工具集中有几乎没有语法开销的箭头函数时,为什么要使用程序化 curry 解决方案?
-
@naomik 可以很容易地说
_.curry,我只是更喜欢 ramda。至于为什么,我个人更喜欢能够一次传递任意数量的参数或一个参数的灵活性。 -
@ftor,James Long 在这方面做了一个很好的系列:"What is a continuation?"、"Implementing a stepping debugger in JavaScript" 和 "Exploring Continuations: Resumable Exceptions"。他使用了他编写的一个实用程序,称为Unwinder,它主要只是对如何在 JS 中实现 call/cc 的探索/演示。免责声明:这一切都非常复杂。
标签: javascript functional-programming monads continuations callcc