如何在Scheme中使用call / cc进行非本地退出

时间:2014-03-23 05:59:51

标签: scheme

目前,我正在学习Scheme语言。 我对如何使用call-with-current-continuation感到困惑。(call / cc) 为了更好地理解它,我为非本地出口编写了一个示例代码。 但它无法正常工作。

有谁知道为什么?任何帮助,将不胜感激。 提前致谢

[示例代码]

(define (product ls)
  (call/cc
   (lambda (return)
     (cond
      ((null? ls ) =>
       (begin
         (display "list end")
         (newline)
         1)) ;; NG
         ;;(return 1)) ;; OK

      ((not (number? (car ls))) =>
       (begin
         (display "not number")
         (newline)
         (return 0)))
      (else =>
            (begin
              (display (car ls))
              (newline)
              (* (car ls) (product (cdr ls)))))))))

[repl output]

gosh> (product '(1 2 a 3)) ; it works as I expected.
==> 1
==> 2
==> not number
==> 0 (return)

gosh> (product '(1 2 3)) ;; it doesn't work as I expected. I expect 6 as return value.
==> 1
==> 2
==> 3
==> list end
*** ERROR: invalid application: (1 #t)

1 个答案:

答案 0 :(得分:4)

这里有几件事情。

首先,看起来您插入cond子句的=>导致了问题。在Scheme中,=>具有特殊含义......您不想要。拿出来,我想你会发现你的代码表现得像你期望的那样。

但是:你使用call / cc 而不是实际导致非本地退出,因为我相信你的意图。也就是说,我的猜测是你希望零点绕过所有等待的乘法,但事实并非如此。要看到这一点,请将0更改为无法乘以的字符 - 比如字符串"not a number" - 并观察它失败。

这是因为您在每次调用函数时重新绑定return。我想你可能真的想要这样的东西:

(define (product ls)
  (call/cc
   (lambda (return)
     (letrec ([loop
              (lambda (ls)
                (cond
                  ((null? ls )
                   (begin
                     (display "list end")
                     (newline)
                     1)) ;; NG
                  ;;(return 1)) ;; OK

                  ((not (number? (car ls)))
                   (begin
                     (display "not number")
                     (newline)
                     (return "not a number")))
                  (else 
                   (begin
                     (display (car ls))
                     (newline)
                     (* (car ls) (loop (cdr ls)))))))])
       (loop ls)))))

(product '(1 2 a 3))

...产生此输出:

1
2
not number
"not a number"
>