1

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点在tosuccess(letcc var (success a)) . bline中的应用到底是什么意思

(letcc success 
       (letcc var (success a)) . b)

try?或者可以换一种方式问:try建立的定义的哪一部分try被评估为bifvar被调用a

编辑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
4

3 回答 3

1

让我们尝试看看会发生什么。我正在使用 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)

第一步:编译文件:

(科幻“尝试”)

这将生成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,当你success用 value调用2时,在(try var (var '(2)) 4)你跳出 1 层的4情况下,将返回第一个延续的序列。

于 2020-02-20T07:21:13.603 回答
1

语法规则是模式匹配。点表示一对中的carand cdr,就像lambda/中的其余参数一样define

(define (my-list . args)
  args)

列表只是嵌套的对。例如。(1 2 3)只是花哨的展示方式(1 . (2 . (3 . ())))

因此(this is random symbols in a list)(try var a . b)通过try匹配thisis匹配varrandom匹配a(symbols in a list)匹配进行匹配b

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

于 2020-02-19T14:24:20.737 回答
1

我不是 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是一个延续,它从内部形式返回其参数letcc,在那里它们被忽略。Ife被调用,那是你结束的地方,然后<b><c>正常方式进行评估(我只放了不止一件事,因为我可以,它处理整个. ...事情)。if在 的求值过程中e 没有<a>被调用, thensuccess 调用,它也是一个延续,然后返回<a>整个表单的求值结果。

至少我认为这就是发生的事情。


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

(module+ test
  (require rackunit))

(define-syntax let/cc 
  (syntax-rules () 
    ((letcc 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))
于 2020-02-19T17:44:52.703 回答