首页 > 其他 > 详细

Teach Yourself Scheme in Fixnum Days 13 Jump跳转

时间:2014-02-17 01:52:53      阅读:465      评论:0      收藏:0      [点我收藏+]

Jumps

One of the signal features of Scheme is its support for jumps or nonlocal control. Specifically, Scheme allows program control to jump to arbitrarylocations in the program, in contrast to the more restrained forms of program control flow allowed by conditionals and procedure calls. Scheme’s nonlocal control operator is a procedure named call?with?current?continuation. We will see how this operator can be used to create a breathtaking variety of control idioms.

scheme 一个显著的特性是其支持跳转<Jump>或非局部控制<nonlocal contral>。具体地说,scheme 允许程序控制流跳转到程序的任意地方,不像通过条件语句和函数调用等控制跳转那么局限。
scheme 跳转操作是通过 call-with-current-continuation <简写形式:call/cc>过程来实现的。下面我们将会看到如何通过该过程来实现许多惊人的控制流程<control idioms>。

13.1  call?with?current?continuation

The operator call?with?current?continuation calls its argument, which must be a unary procedure, with a value called the “current continuation”. If nothing else, this explains the name of the operator. But it is a long name, and is often abbreviated call/cc.1

The current continuation at any point in the execution of a program is an abstraction of the rest of the program. Thus in the program

 

call-with-current-continuation 过程的参数是一个单参数<unary>过程,单参数过程的参数被绑定为"current continuation"。
 
在程序的任何地方,"current continuation" 都是 "the rest of the program" 的抽象。因此,下面语句中:
(+ 1 (call/cc
       (lambda (k)
         (+ 2 (k 3)))))

 

the rest of the program, from the point of view of the call/cc-application, is the following program-with-a-hole (with [] representing the hole):

 call/cc 过程的 "the rest of the program" 就是下面的有一个 [] 的语句

(+ 1 [])

 

In other words, this continuation is a program that will add 1 to whatever is used to fill its hole.

This is what the argument of call/cc is called with. Remember that the argument of call/cc is the procedure

 

也就是说,这个 continuation 就是用任何值来来替 [] 进而与 1 相加的程序。
 
下面是 call/cc 过程的参数<必须为一个单参数过程>:
(lambda (k)
  (+ 2 (k 3)))

 

This procedure’s body applies the continuation (bound now to the parameterk) to the argument 3. This is when the unusual aspect of the continuation springs to the fore. The continuation call abruptly(突然地) abandons its own computation and replaces it with the rest of the program saved in k! In other words, the part of the procedure involving the addition of 2 is jettisoned(抛弃), and k’s argument 3 is sent directly to the program-with-the-hole:

 

<过程体 k 调用随后的语句不会被执行,直接跳转>
随后用 3 代替 []:
(+ 1 [])

 

 

The program now running is simply

 

(+ 1 3)

 

 

which returns 4. In sum,

 

(+ 1 (call/cc
       (lambda (k)
         (+ 2 (k 3)))))
=>  4

 

 

The above illustrates what is called an escaping continuation, one used to exit out of a computation (here: the (+ 2 []) computation). This is a useful property, but Scheme’s continuations can also be used to return to previously abandoned contexts, and indeed to invoke them many times. The “rest of the program” enshrined in a continuation is available whenever and how many ever times we choose to recall it, and this is what contributes to the great and sometimes confusing versatility of call/cc. As a quick example, type the following at the listener:

 

上面用例子说明了用来跳出计算的 escaping continuation。但是,在 scheme 中,continuation 也可以被用来多次跳转到程序已经执行过的地方。
先睹为快,看下面程序:
(define r #f)

(+ 1 (call/cc
       (lambda (k)
         (set! r k)
         (+ 2 (k 3)))))
=>  4

 

 

The latter expression returns 4 as before. The difference between this use of call/cc and the previous example is that here we also store the continuation k in a global variable r.

Now we have a permanent record of the continuation in r. If we call it on a number, it will return that number incremented by 1:

最后一个表达式返回 4,这里的 call/cc 调用与前面的例子中有一个不同,就是在跳转前我们把 "the continuation" 绑定到 r 全局变量中。现在,我们就有了一个在 r 变量存储的 "the continuation" 记录,该 "the continuation" 为 (+ 1 []),因此,以后,我们以一个数值调用 r 时,都会使程序控制流跳转到程序中的 "the continuation" 的位置,并且用该数值代替 [] 进行以后的计算。
因此,当我们用 5 调用 r 时返回 6:
(r 5)
=>  6

 

Note that r will abandon its own continuation, which is better illustrated by embedding the call to r inside some context:

 而把 r 调用嵌入在某些环境中更能证明 continuation 跳转的作用:

(+ 3 (r 5))
=>  6

 r 调用会将程序控制流直接跳转到 "the continuation" (+ 1 []) 处,再用 5 替换 [],执行那里的代码。

 

The continuations provided by call/cc are thus abortive continuations.

 

13.2  Escaping continuations

Escaping continuations are the simplest use of call/cc and are very useful for programming procedure or loop exits. Consider a procedure list?productthat takes a list of numbers and multiplies them. A straightforward recursive definition for list?product is:

 

 

(define list-product
  (lambda (s)
    (let recur ((s s))
      (if (null? s) 1
          (* (car s) (recur (cdr s)))))))

 

 

There is a problem with this solution. If one of the elements in the list is 0, and if there are many elements after 0 in the list, then the answer is a foregone conclusion. Yet, the code will have us go through many fruitless recursive calls to recur before producing the answer. This is where an escape continuation comes in handy. Using call/cc, we can rewrite the procedure as:

 但是上面的计算方法有一个问题,就是列表中有一个元素为 0 并且其后还有许多个元素,当计算到 0 时,结果就可以确定为 0,而不用在与其后的元素相乘。此时,我们可以用 escaping continuations 重写 list-product 过程来避免这些无效的计算:

 

(define list-product
  (lambda (s)
    (call/cc
      (lambda (exit)
        (let recur ((s s))
          (if (null? s) 1
              (if (= (car s) 0) (exit 0)
                  (* (car s) (recur (cdr s))))))))))

 

 

If a 0 element is encountered, the continuation exit is called with 0, thereby avoiding further calls to recur.

更多:

http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-15.html#node_chap_13

http://lispor.is-programmer.com/posts/23638.html

 

Teach Yourself Scheme in Fixnum Days 13 Jump跳转

原文:http://www.cnblogs.com/youxin/p/3551399.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!