Racket 如何解释球拍中call/cc的有趣行为?
联合收割机必须使用二进制运算符bin映射reduce列表,但如果发现任何值不符合谓词pred?,则必须返回exc,如果发现任何此类值,则不得对列表执行任何计算 这是一个简单的延拓问题Racket 如何解释球拍中call/cc的有趣行为?,racket,Racket,联合收割机必须使用二进制运算符bin映射reduce列表,但如果发现任何值不符合谓词pred?,则必须返回exc,如果发现任何此类值,则不得对列表执行任何计算 这是一个简单的延拓问题 #lang racket (define (id x) x) (define (const x) (lambda (_) x)) (define (combine pred? bin zero exc) (call/cc (lambda (exit) (letrec
#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,define的延续,是为了定义一个函数,但是有人能给出更多的细节吗?例如,涉及哪些语法转换?思考一下您在这里必须遵循的顺序:
(define product (combine ....))
在这里,您首先评估联合收割机。。。而continuation是程序的其余部分,首先将计算值存储为名称乘积。从withing f调用continuation将直接返回到重新存储产品
通过调用产品“1 2 3 0 4”,您正在重新定义产品,因为它是程序的延续,call/cc捕获延续
在第二次尝试中,您进行了真正的重构,将其包装在lambda中,并使用相同的参数调用f。它只是延迟调用/抄送发生的时间,从而延迟继续中包含的内容。在这个版本中,延续是产品之后的任何内容。。。而不是定义产品中的产品设置…这可以用方案本身来解释,还是在实现中我们必须看语言之外的东西?@Rdgstv lang racket不遵循标准,但它似乎符合!r6rs报告:实现职责:实现应检测到的延续被多次调用。如果实现检测到这一点,它必须使用条件类型和断言引发异常。。Racket实现支持许多标准方案报告语言。我已经看到许多已经定义和设置的scheme实现!与原语相同。@Rdgstv理解call/cc。call/cc所做的就是将continuation作为函数公开。不管怎样,许多Scheme实现都会将代码转换为CPS,但那些不这样做的人会将代码转换为call/cc。CPS调用/cc只是定义调用/cc主体c主体lambda值实际延续c值c。像define这样的特殊形式在CPS中很难实现,因为我们没有从函数中定义顶级绑定的原语。函数内部的define变成了一个letrec,这不是我们想要的