提交 8564fdf8 编写于 作者: G guenchi

add callcc

上级 f70f3d86
call/cc表达式,提取当前位置的延续。
如以下的程序:
```scheme
(+
(*
(call/cc
(lambda (c)
(+
(c 2)
3)))
5)
8)
```
可以先简化为
```scheme
(+
(*
(call/cc …)
5)
8)
```
什么叫当前位置的延续呢?
比如
```scheme
(+
(* x 5)
8)
```
对于x来说,它的延续就是它将要被做的事。这里就是,*5然后+8。
这个延续如何用代码表示呢?
```scheme
(lambda (k)
(+
(* k 5)
8))
```
那么对于x 也就是`(call/cc …)`的延续就是
```scheme
(lambda (k)
(+
(* k 5)
8))
```
现在来看(call/cc ...)语句内部,当call/cc取得当前位置的延续后,它需要一个回调函数来使用这个延续。对吧?因为从这里控制流开始向回调函数处跳转,而不是返回到(call/cc ...)所在的当前栈。
也就是说,`(+ (* (call/cc …)5) 8)` 的加法和乘法是永远也不会执行的!从call/cc开始,就走了,走了,永远也不回来了。去哪了,去(call/cc f)的回调函数f那里了。
然后来看回调函数f:
```scheme
(lambda (c)
(+
(c 2)
3))
```
f被以call/cc得到的延续为参数调用,同时这个延续也作为f的回调函数,请注意后一点。
参数c在这里带入
```scheme
(lambda (k)
(+
(* k 5)
8))
```
那么回调函数f在这里的求值就是:
```scheme
((lambda (c)
(+
(c 2)
3))
(lambda (k)
(+
(* k 5)
8)))
```
注意 这里的求值是永远不会被返回的。(普通scheme程序这里会得到21)
因为回调函数f,在求值时将控制流传递给了它的回调函数c,如果使用有return的语言来表达的话。
```javascript
var f = function(c){
var x = c(2);
return x;
x+3;
}
```
x+3是永远不会执行的。
这样的返回方式是call/cc的特殊之处,正是这样,它才能暴露出整个程序的控制流。
所以整个程序的求值返回了
```scheme
((lambda (c)
(c 2))
(lambda (k)
(+
(* k 5)
8)))
```
的结果。
注意这个结果和`(+ (* x 5) 8)`这个外层函数一点关系都没有,它已经成为过去了。
那么现在我们就很好理解
```scheme
(set! *this* c)
(*this* 10)
```
这样的写法了。延续c只不过被储存了起来,随时调用罢了。而这个c在当下与过去的外层函数一点关系没有了。
```scheme
(+
(*
(call/cc
(lambda (c)
(set! *this* c)
1))
5)
8)
```
在这个例子里,因为回调函数也就是延续c一直没有被调用。
那么call/cc的回调函数会返回1,结果是13。
但这里我们把延续存起来了,于是:
```scheme
(*this* 2)
```
相当于
```scheme
((lambda (c)
(c 2))
(lambda (k)
(+
(* k 5)
8)))
```
得到 18
```scheme
(*this* 3)
```
相当于
```scheme
((lambda (c)
(c 3))
(lambda (k)
(+
(* k 5)
8)))
```
得到 23
可以看到这里的 *this* 等于c 和原函数 `(+ (* x 5) 8)` 一点关系没有了。
\ No newline at end of file
{
"node_id": "scheme-2575c2cd26f847ea93415549c6c026a2",
"keywords": [],
"keywords_must": [],
"keywords_forbid": [],
"group": 0,
"subtree": ""
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册