【发布时间】:2012-01-07 02:26:55
【问题描述】:
Wikipedia 提到“在任何支持闭包和适当尾调用的语言中,都可以编写连续传递风格的程序并手动实现 call/cc。”
如何在 javascript 中实现此功能?我知道javascript不做tco,但假设堆栈空间没有用完
【问题讨论】:
标签: javascript callcc
Wikipedia 提到“在任何支持闭包和适当尾调用的语言中,都可以编写连续传递风格的程序并手动实现 call/cc。”
如何在 javascript 中实现此功能?我知道javascript不做tco,但假设堆栈空间没有用完
【问题讨论】:
标签: javascript callcc
有可能
https://github.com/zaoqi/callcc.js/blob/master/callcc.js
async function callcc(f){
return await new Promise((resolve,reject)=>{
const resolve_packed=(v)=>{
resolve(v)
return new Promise((resolve,reject)=>{})
}
f(resolve_packed).then(resolve).catch(reject)
})
}
使用它:
test('test1',()=>{
expect.assertions(1)
expect((()=>{
async function q(k,v){
console.log('testing1')
await k(v)
}
return callcc(async function(k){
console.log('testing0')
await q(k,133)
console.error('test error')
})
})()).resolves.toBe(133)
})
【讨论】:
async function callcc(f) { return await new Promise(...) } 等同于async function callcc(f) { return new Promise(...) } 等同于function callcc(f) { return new Promise(...) } 等同于callcc = f => new Promise(...)
是的,这是可能的。请参阅此question。这就是你将如何实现它:
Function.prototype.async = async;
function async() {
setTimeout.bind(null, this, 0).apply(null, arguments);
}
function callcc(f, cc) {
f.async(cc);
}
那么你可以这样使用它:
pythagoras.async(3, 4, alert);
function pythagoras(x, y, cont) {
callcc.async(square.bind(null, x), function cc(x_squared) {
callcc.async(square.bind(null, y), function cc(y_squared) {
add.async(x_squared, y_squared, cont);
});
});
}
function square(x, cont) {
multiply.async(x, x, cont);
}
function multiply(x, y, cont) {
cont.async(x * y);
}
function add(x, y, cont) {
cont.async(x + y);
}
您可以在这里摆弄演示:http://jsfiddle.net/brZrd/
【讨论】:
无法在 JavaScript 中编写 call/cc 实现:
JavaScript 不满足“正确的尾调用”的要求(没有额外的堆栈创建)。但是,我相信使用异常的 form 延续是可能的,例如在 Jetty 中发现的那种。 “CPS”就像传递一个函数对象一样简单,尽管最终它也会遇到堆栈问题,除非偶尔退出。
编码愉快。
【讨论】:
setTimeout() 清除堆栈来做到这一点?