0

我的背景是 Javascript、Python 和一点 Haskell。嗨,我是 Scheme 的新手(1 天大)。我想了解以下 2 个代码片段之间的区别。

(define onePlus (lambda (v) (+ 1 v)))
(onePlus 4) ; 5 

使用 CallCC

(define anotherOnePlus 0)
(+ 1 (call/cc (lambda (k) (set! anotherOnePlus k) (k 4)))) ; 5
(anotherOnePlus 4); 5

为什么有人想用第二种方法来掌握你所居住的功能。从更大的角度来看,我错过了什么?

Scope 是否有任何限制来获取功能?

(define temp 0)
(+ 1 (+ 2 (+ 3 (call/cc (lambda (k) (set! temp k) (k 4)))))) ; 10
(temp 5) ; 11

这绝对是 JS 中的样子h => 1 + 2 + 3 + h。如果我想掌握(+ 3 h)这意味着我需要将它写在单独的行中怎么办?

4

1 回答 1

1

如果您要使用不同的值再次进行计算,那么进行第二次计算的唯一原因。在实践中,它是一个 goto,如果你的延续没有被定界,它就是一个无限循环。例如。尝试这个:

(define anotherOnePlus 0)
(let ()
  (+ 1 (call/cc (lambda (k) (set! anotherOnePlus k) (k 4)))) ; 5
  (anotherOnePlus 4)); 5

您将永远不会得到答案,因为(anotherOnePlus 4)将您带回到(+ 1 4)继续(anotherOnePlus 4)带您再次回来。

功能没有限制。只要它被引用,它就不会被垃圾收集。

一个更好的演示方式call/cc将是一个更好的例子。如果您要实现map多个列表,则需要获取cars除非列表之一为空,否则结果应该为空。您可以通过首先迭代整个列表来确保没有空列表来做到这一点:

(define (cars-1 lsts)
  (define (have-elements? lsts)
    (cond ((null? lsts) #t)
          ((null? (car lsts)) #f)
          (else (have-elements? (cdr lsts)))))
  (define (cars lsts)
    (if (null? lsts)
        '()
        (cons (caar lsts)
              (cars (cdr lsts)))))
  (if (have-elements? lsts)
      (cars lsts)
      '()))

但是有一个聪明的解决方案,如果你找到一个你保释的空元素,你就这样做。这可以通过这样的延续来完成:

(define (cars lsts)
  (define (cars lsts k)
    (cond ((null? lsts) (k '()))
          ((null? (car lsts)) '())
          (else (cars (cdr lsts)
                      (lambda (res)
                        (k (cons (caar lsts)
                              res)))))))
  (cars lsts values))

现在,如果我们可以让语言来做延续,而我们只是选择是否使用它们,那不是很好吗?计划为您做到这一点。你这样写:

(define (cars lsts)
  (call/cc
   (lambda (bail)
     (define (cars lsts)
       (cond ((null? lsts) '())
             ((null? (car lsts)) (bail '()))
             (else (cons (caar lsts)
                         (cars (cdr lsts))))))
     (cars lsts))))

现在,如果您查看SRFI-1 列表库的参考实现,您会发现他们实际上是这样做的。

于 2019-12-15T14:45:06.993 回答