如何解释在Racket中调用/ cc的有趣行为?

时间:2017-12-05 22:52:29

标签: racket

combine必须映射使用二元运算符bin减少列表,但如果找到任何未通过谓词exc的值,并且如果找到任何值,则必须返回pred?这样的值不能在列表上执行任何计算。

这是一个简单的延续问题。

#lang racket

(define (id x)
  x)

(define (const x)
  (lambda (_) x))

(define (combine pred? bin zero exc)
  (call/cc
   (lambda (exit)
     (letrec
         ((f (lambda (xs)
               (if (empty? xs)
                   zero
                   (if (pred? (first xs))
                       (exit exc)
                       (bin (first xs) (f (rest xs))))))))
       f))))

(define product
  (combine zero?
           *
           1
           0))

(product '(1 2 3 0 4))

代码几乎可以工作,但它有一个非常微妙的错误。

它引发了以下异常:

define-values: assignment disallowed;
 cannot re-define a constant
  constant: product

很容易让它发挥作用。只需要做一些小改动:

(define (combine pred? bin un zero exc)
  (lambda (ys)
    (call/cc
     (lambda (exit)
       (letrec
           ((f (lambda (xs)
                 (if (empty? xs)
                     zero
                     (if (pred? (first xs))
                         (exit exc)
                         (bin (first xs) (f (rest xs))))))))
         (f ys))))))

我看到问题是,Racket继续定义是定义一个函数,但任何人都可以提供更多细节吗?例如,涉及哪些合成转换?

1 个答案:

答案 0 :(得分:1)

想想你必须拥有的顺序:

(define product (combine ....))

这里首先评估(combine ...),继续是程序的其余部分,首先将计算值存储为名称product。调用继续从f跳转到正好再次存储product

通过调用(product '(1 2 3 0 4)),您正在重新定义product,因为它是程序的延续,而call/cc会捕获延续。

在你的第二次尝试中,你做了一个真正的重构,将它包装在lambda中,并用相同的参数调用f。它只是在call/cc发生时延迟,因此包含在延续中。在此版本中,延续是(product ...)之后的任何内容,而不是product

中的设置(define product ...)