Scheme/"The Seasoned Schemer":关于"try"函数定义的语法问题

Scheme/"The Seasoned Schemer": Question about the syntax of the definition of "try" function

Felleisen 和 Friedman 在他们的书 "The Seasoned Schemer" 中介绍了 try 函数。根据http://community.schemewiki.org/?seasoned-schemer,这个函数可以定义为

(define-syntax try
  (syntax-rules ()
    ((try var a . b)
     (letcc success 
       (letcc var (success a)) . b))))

其中 letcc 定义为

(define-syntax letcc 
  (syntax-rules () 
    ((letcc var body ...) 
     (call-with-current-continuation 
       (lambda (var)  body ... ))))) 

现在,虽然我理解了 try 的作用以及如何使用它,但我很难遵循它的正式定义。 letcc应用于success(letcc var (success a)) . b

中的点到底是什么意思
(letcc success 
       (letcc var (success a)) . b)

try?或者可能会提出不同的问题:如果 a 中调用了 vartry 定义的哪一部分确定 try 被计算为 b

编辑 1: 抱歉,letcc 的定义不完整。添加了缺失的第一行。

编辑2:下面的代码可以在Racket中运行

(define-syntax letcc
   (syntax-rules ()
                 ((letcc var body ...)
                  (call-with-current-continuation
                    (lambda (var)  body ... )))))

 (define-syntax try
   (syntax-rules ()
                 ((try var a . b)
                  (letcc success
                         (letcc var (success a)) . b))))

(try var (+ 1 1) 4)
; output: 2

(try var (var '(2)) 4)
; output: 4

语法规则是模式匹配。点表示一对的 carcdr 就像 lambda / define:

中的其余参数一样
(define (my-list . args)
  args)

列表只是嵌套的对。例如。 (1 2 3) 只是显示 (1 . (2 . (3 . ()))) 的奇特方式。

所以(this is random symbols in a list)将通过try匹配this匹配(try var a . b)is匹配varrandom匹配a,而 (symbols in a list) 匹配 b.

当您在扩展中看到相同的内容时,这意味着代码应该在点之后拼接匹配项。例如,前面示例中的 (var . b) 变为 (is symbols in a list)。它类似于 b ... 但对系统来说更便宜。

我不是 Scheme 宏语法复杂性方面的专家,但我认为 try 的等效定义是:

(define-syntax try 
  (syntax-rules () 
    ((try var a b ...) 
     (letcc success 
       (letcc var (success a)) b ...))))

我发现这肯定更容易阅读。

(try e <a> <b> <c>)(任一版本,至少在 Racket 中)然后扩展为

(letcc success
  (letcc e
    (success <a>))
  <b> <c>)))

那么,当 <a> 被评估时,e 是一个延续,returns 它的参数来自内部 letcc 形式,在那里它们被忽略.如果 e 被调用,那就是你最终的结果,然后 <b><c> 以正常方式进行评估(我只放了不止一件事,因为我可以,它处理整个 . ... 东西)。如果 e 不是 在计算 <a> 期间被调用,那么 success 被调用,并且它也是一个延续,然后 returns 从整个表格中评估 <a> 的结果。

至少我认为是这样。


下面是我用来测试我理解的东西的一大块 Racket。

(module+ test
  (require rackunit))

(define-syntax let/cc 
  (syntax-rules () 
    ((let/cc var body ...) 
     (call-with-current-continuation 
       (lambda (var) body ... ))))) 

(define-syntax try 
  (syntax-rules () 
    ((try var a b ...) 
     (let/cc success 
       (let/cc var (success a)) b ...))))

(module+ test
  (check-eqv?
   (try fail (+ 1 1) 4)
   2)

  (check-eqv?
   (try fail (fail '(2)) 4)
   4)

  (check-eqv?
   (try fail
        (begin 1 (fail) (error "failed to fail"))
        4 5 6)
   6))

让我们试试看会发生什么。我正在使用 mit-scheme。

文件try.scm:

(define-syntax letcc
   (syntax-rules ()
                 ((letcc var body ...)
                  (call-with-current-continuation
                    (lambda (var)  body ... )))))

 (define-syntax try
   (syntax-rules ()
                 ((try var a . b)
                  (letcc success
                         (letcc var (success a)) . b))))

(try var (+ 1 1) 4)

(try var (var '(2)) 4)

第一步:编译文件:

(sf "try")

这将生成 try.bin

第二步,打印脱糖语法:

(pp (unsyntax (fasload "try")))

;Loading "try.bin"... done
 ................
 (call-with-current-continuation
  (lambda (success)
    (call-with-current-continuation (lambda (var) (success (+ 1 1))))
    4))
 (call-with-current-continuation
  (lambda (success)
    (call-with-current-continuation (lambda (var) (success (var '(2)))))
    4)))

现在您可以清楚地看到执行的内容以及结果。

(try var (+ 1 1) 4)的情况下,你跳出2个嵌套的calcc,因为你用值2调用success,而在(try var (var '(2)) 4)你跳出第 1 层,返回第 1 层延续序列中的 4