Scheme 哪种最简单的评估模型可以解释call/cc?

Scheme 哪种最简单的评估模型可以解释call/cc?,scheme,semantics,evaluation,interpretation,callcc,Scheme,Semantics,Evaluation,Interpretation,Callcc,TL;DR:call/cc(半)正式地说是做什么的 长版本:我对continuations和call/cc略知一二,但对形式上的理解不强。我想要一个 在本文中,我们给出了替换模型和一个元循环解释器。在施里拉姆·克里希那穆蒂的作品中,我们看到了一种环境和商店通行的风格。在我学习uni的编译器课程中,我通过操作堆栈来计算Java表达式 call/cc最简单的评估模型是什么?您如何在其中表达call/cc?TL;DRcall/cc允许您点击内部代码,这样您就可以使用continuations,而无需以

TL;DR:call/cc(半)正式地说是做什么的

长版本:我对continuations和call/cc略知一二,但对形式上的理解不强。我想要一个

在本文中,我们给出了替换模型和一个元循环解释器。在施里拉姆·克里希那穆蒂的作品中,我们看到了一种环境和商店通行的风格。在我学习uni的编译器课程中,我通过操作堆栈来计算Java表达式

call/cc最简单的评估模型是什么?您如何在其中表达call/cc?

TL;DR
call/cc
允许您点击内部代码,这样您就可以使用continuations,而无需以continuationpassing样式编写代码。最好的评估模型是替代模型,前提是您不使用
设置
并从CPS代码查看它

想象一下这个小程序

(define (sum-list lst)
  (cond ((null? lst) 0)
        ((number? (car lst)) (+ (car lst) (sum-list (cdr lsr))))
        (else (sum-list (cdr lsr)))))

(display (sum-list '(1 2 3 4))) ; displays 10
想象一下,如果点击
else
项,您希望结果为
1337
。如果不重写整件事,你会怎么做?你不能。但是,大多数方案实现都会将CPS转换为代码,而更改代码则非常简单:

(define (sum-list& lst k)
  (null?& lst
          (lambda (nlst?)
            (if& nlst?
                 (lambda ()
                   (k 0))
                 (lambda ()
                   (car& lst
                         (lambda (car-lst)
                           (number?& car-lst
                                     (lambda (ncl?)
                                       (if& ncl?
                                            (lambda ()
                                              (cdr& lst
                                                    (lambda (clst)
                                                      (sum-list& clst
                                                                 (lambda (sclst)
                                                                   (+& car-lst sclst k))))))
                                            (lambda ()
                                              (cdr& lst
                                                    (lambda (clst)
                                                      (sum-list& clst k))))))))))))))
(sum-list& '(1 2 3 4)
           (lambda (sum)
             (display& sum halt)))
cond
是一个宏,因此它是
if&
调用您看到的。我知道你在想什么。为什么不首先告诉程序员这样做呢?开玩笑

如果您将第二个
If&
中的第二个continuation更改为
(lambda()(k 1337))
,那么就完成了。尽管CPS很漂亮,但读写都很糟糕,但既然编译器是这样做的,难道就没有办法在第一种方式下编写代码,同时仍然可以控制代码流吗?通过
call/cc
启用“两个世界中最好的一个”<代码>呼叫/cc
在CPS中是这样的:

(define (call/cc& f& continuation)
  (define (exit& value actual-continuation)
    (continuation value))
  (f& exit& continuation))
(define (sum-list& lst k)
  (call/cc&
   (lambda (k& real-k)
     (define (helper& lst k)
       (null?& lst
               (lambda (nlst?)
                 (if& nlst?
                      (lambda ()
                        (k 0))
                      (lambda ()
                        (car& lst
                              (lambda (car-lst)
                                (number?& car-lst
                                          (lambda (ncl?)
                                            (if& ncl?
                                                 (lambda ()
                                                   (cdr& lst
                                                         (lambda (clst)
                                                           (helper& clst
                                                                    (lambda (sclst)
                                                                      (+& car-lst sclst k))))))
                                                 (lambda ()
                                                   (k& 1337 real-k))))))))))))
     (helper& lst real-k))
     k))


(sum-list& '(1 2 3 4)
           (lambda (sum)
             (display& sum halt)))
这根本没什么用。它传递
exit&
,调用时忽略程序的实际延续,并使用
call/cc&
调用的原始延续调用值。使用列表
”(1 2 3#f)
您将有3个嵌套的continuation等待添加结果,但所有这些都需要取消。如果在计算之前选择连续值,则会自动取消。 就这样。当您使用它编写代码时,您不需要执行完整的CPS,只需继续您想要的内容就可以像这样思考
call/cc

(define (sum-list lst)
  (call/cc
   (lambda (k)
     (define (helper lst)
       (cond ((null? lst) 0)
             ((number? (car lst))
              (+ (car lst) (helper (cdr lst))))
             (else (k 1337))))
     (helper lst))))
(define (sum-list lst)
  (define (helper lst sum)
    (cond ((null? lst) sum)
          ((number? (car lst)) (helper (cdr lst) (+ sum (car lst))))
          (else 1337)))
  (helper lst 0))
在CPS中将其转换为:

(define (call/cc& f& continuation)
  (define (exit& value actual-continuation)
    (continuation value))
  (f& exit& continuation))
(define (sum-list& lst k)
  (call/cc&
   (lambda (k& real-k)
     (define (helper& lst k)
       (null?& lst
               (lambda (nlst?)
                 (if& nlst?
                      (lambda ()
                        (k 0))
                      (lambda ()
                        (car& lst
                              (lambda (car-lst)
                                (number?& car-lst
                                          (lambda (ncl?)
                                            (if& ncl?
                                                 (lambda ()
                                                   (cdr& lst
                                                         (lambda (clst)
                                                           (helper& clst
                                                                    (lambda (sclst)
                                                                      (+& car-lst sclst k))))))
                                                 (lambda ()
                                                   (k& 1337 real-k))))))))))))
     (helper& lst real-k))
     k))


(sum-list& '(1 2 3 4)
           (lambda (sum)
             (display& sum halt)))
呼叫/cc
总是可以避免的。我们的示例可以重写为返回1337,如下所示:

(define (sum-list lst)
  (call/cc
   (lambda (k)
     (define (helper lst)
       (cond ((null? lst) 0)
             ((number? (car lst))
              (+ (car lst) (helper (cdr lst))))
             (else (k 1337))))
     (helper lst))))
(define (sum-list lst)
  (define (helper lst sum)
    (cond ((null? lst) sum)
          ((number? (car lst)) (helper (cdr lst) (+ sum (car lst))))
          (else 1337)))
  (helper lst 0))
这是尾部递归,它不创建连续性,而是累积。为完整起见,以下是CPS版本:

(define (helper& lst sum k)
  (null?& lst
          (lambda (nlst)
            (if& nlst
                 (lambda () (k sum))
                 (lambda ()
                   (car& lst
                       (lambda (cl)
                         (number?& cl
                                 (lambda (ncl?)
                                   (if& ncl?
                                        (lambda ()
                                          (cdr& lst
                                                (lambda (cdrl)
                                                  (+& sum
                                                      cl
                                                      (lambda (scl)
                                                        (helper& cdrl
                                                                 scl
                                                                 k))))))
                                        (lambda () (k 1337))))))))))))


(define (sum-list& lst k)
  (helper& lst 0 k))
TL;DR
call/cc
允许您点击内部代码,这样您就可以使用continuations,而无需以continuationpassing样式编写代码。最好的评估模型是替代模型,前提是您不使用
设置
并从CPS代码查看它

想象一下这个小程序

(define (sum-list lst)
  (cond ((null? lst) 0)
        ((number? (car lst)) (+ (car lst) (sum-list (cdr lsr))))
        (else (sum-list (cdr lsr)))))

(display (sum-list '(1 2 3 4))) ; displays 10
想象一下,如果点击
else
项,您希望结果为
1337
。如果不重写整件事,你会怎么做?你不能。但是,大多数方案实现都会将CPS转换为代码,而更改代码则非常简单:

(define (sum-list& lst k)
  (null?& lst
          (lambda (nlst?)
            (if& nlst?
                 (lambda ()
                   (k 0))
                 (lambda ()
                   (car& lst
                         (lambda (car-lst)
                           (number?& car-lst
                                     (lambda (ncl?)
                                       (if& ncl?
                                            (lambda ()
                                              (cdr& lst
                                                    (lambda (clst)
                                                      (sum-list& clst
                                                                 (lambda (sclst)
                                                                   (+& car-lst sclst k))))))
                                            (lambda ()
                                              (cdr& lst
                                                    (lambda (clst)
                                                      (sum-list& clst k))))))))))))))
(sum-list& '(1 2 3 4)
           (lambda (sum)
             (display& sum halt)))
cond
是一个宏,因此它是
if&
调用您看到的。我知道你在想什么。为什么不首先告诉程序员这样做呢?开玩笑

如果您将第二个
If&
中的第二个continuation更改为
(lambda()(k 1337))
,那么就完成了。尽管CPS很漂亮,但读写都很糟糕,但既然编译器是这样做的,难道就没有办法在第一种方式下编写代码,同时仍然可以控制代码流吗?通过
call/cc
启用“两个世界中最好的一个”<代码>呼叫/cc
在CPS中是这样的:

(define (call/cc& f& continuation)
  (define (exit& value actual-continuation)
    (continuation value))
  (f& exit& continuation))
(define (sum-list& lst k)
  (call/cc&
   (lambda (k& real-k)
     (define (helper& lst k)
       (null?& lst
               (lambda (nlst?)
                 (if& nlst?
                      (lambda ()
                        (k 0))
                      (lambda ()
                        (car& lst
                              (lambda (car-lst)
                                (number?& car-lst
                                          (lambda (ncl?)
                                            (if& ncl?
                                                 (lambda ()
                                                   (cdr& lst
                                                         (lambda (clst)
                                                           (helper& clst
                                                                    (lambda (sclst)
                                                                      (+& car-lst sclst k))))))
                                                 (lambda ()
                                                   (k& 1337 real-k))))))))))))
     (helper& lst real-k))
     k))


(sum-list& '(1 2 3 4)
           (lambda (sum)
             (display& sum halt)))
这根本没什么用。它传递
exit&
,调用时忽略程序的实际延续,并使用
call/cc&
调用的原始延续调用值。使用列表
”(1 2 3#f)
您将有3个嵌套的continuation等待添加结果,但所有这些都需要取消。如果在计算之前选择连续值,则会自动取消。 就这样。当您使用它编写代码时,您不需要执行完整的CPS,只需继续您想要的内容就可以像这样思考
call/cc

(define (sum-list lst)
  (call/cc
   (lambda (k)
     (define (helper lst)
       (cond ((null? lst) 0)
             ((number? (car lst))
              (+ (car lst) (helper (cdr lst))))
             (else (k 1337))))
     (helper lst))))
(define (sum-list lst)
  (define (helper lst sum)
    (cond ((null? lst) sum)
          ((number? (car lst)) (helper (cdr lst) (+ sum (car lst))))
          (else 1337)))
  (helper lst 0))
在CPS中将其转换为:

(define (call/cc& f& continuation)
  (define (exit& value actual-continuation)
    (continuation value))
  (f& exit& continuation))
(define (sum-list& lst k)
  (call/cc&
   (lambda (k& real-k)
     (define (helper& lst k)
       (null?& lst
               (lambda (nlst?)
                 (if& nlst?
                      (lambda ()
                        (k 0))
                      (lambda ()
                        (car& lst
                              (lambda (car-lst)
                                (number?& car-lst
                                          (lambda (ncl?)
                                            (if& ncl?
                                                 (lambda ()
                                                   (cdr& lst
                                                         (lambda (clst)
                                                           (helper& clst
                                                                    (lambda (sclst)
                                                                      (+& car-lst sclst k))))))
                                                 (lambda ()
                                                   (k& 1337 real-k))))))))))))
     (helper& lst real-k))
     k))


(sum-list& '(1 2 3 4)
           (lambda (sum)
             (display& sum halt)))
呼叫/cc
总是可以避免的。我们的示例可以重写为返回1337,如下所示:

(define (sum-list lst)
  (call/cc
   (lambda (k)
     (define (helper lst)
       (cond ((null? lst) 0)
             ((number? (car lst))
              (+ (car lst) (helper (cdr lst))))
             (else (k 1337))))
     (helper lst))))
(define (sum-list lst)
  (define (helper lst sum)
    (cond ((null? lst) sum)
          ((number? (car lst)) (helper (cdr lst) (+ sum (car lst))))
          (else 1337)))
  (helper lst 0))
这是尾部递归,它不创建连续性,而是累积。为完整起见,以下是CPS版本:

(define (helper& lst sum k)
  (null?& lst
          (lambda (nlst)
            (if& nlst
                 (lambda () (k sum))
                 (lambda ()
                   (car& lst
                       (lambda (cl)
                         (number?& cl
                                 (lambda (ncl?)
                                   (if& ncl?
                                        (lambda ()
                                          (cdr& lst
                                                (lambda (cdrl)
                                                  (+& sum
                                                      cl
                                                      (lambda (scl)
                                                        (helper& cdrl
                                                                 scl
                                                                 k))))))
                                        (lambda () (k 1337))))))))))))


(define (sum-list& lst k)
  (helper& lst 0 k))

我发现这篇精彩的演讲(德语)回答了我的问题:

要使用call/CC计算lambda演算,需要传递一个由环境(通常)和调用堆栈组成的计算上下文。调用
call/cc
会创建一个特殊的函数,如continuation对象,它存储求值上下文。将特殊对象应用于表达式
expr
的结果是在continuation对象中捕获的求值上下文中解释
expr
的结果

TL;DR:您可以使用环境和调用堆栈传递解释器实现
call/cc

如果您还希望围绕可变存储线程,那么continuation对象不应该捕获它。相反,在调用延续时,将存储作为参数传递给恢复的求值上下文中的解释。(存储可以是线性类型。)

这里是Haskell中的一个这样的实现。下面是一个您可能需要计算的示例表达式:
解释0(应用程序(Lambda)1,(CallCC(Lambda)2,(应用程序(变量2)(Lambda)3,(变量