【问题标题】:Clarification on callCCcallCC的澄清
【发布时间】:2020-04-02 03:26:26
【问题描述】:

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

(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),这意味着我需要将它写在单独的行中怎么办?

【问题讨论】:

  • 如果这是你使用 Scheme 的第一天,你不应该从延续 :) 开始。它们不是范围规则的“限制”。将它们视为更好地控制执行堆栈的一种方式,但您很少需要在日常工作中使用它们。
  • Haskell 只有 delimited 延续。 Scheme 的 undelimited 延续可以保存并重新输入 any 上下文。调用从.... (call/cc (lambda (k) ....)) .... 获取的(k val) 会将val 返回到等待该(call/cc (lambda (k) ....)) 表单返回值的上下文中。我知道的唯一模拟是 C 的longjmpTSPL 有更多。还有其他关于 Scheme 的书籍。
  • 感谢@WillNess 将 Haskell 与 Scheme 区分开来,在 Haskell 中比较 Scheme 和 callCC 时我感到很困惑。我发现这个链接很有帮助blogs.msdn.microsoft.com/ashleyf/2010/02/11/…
  • 请注意,尽管 CPS 中的“延续”不是 Scheme 的完整的、“真实的”无定界延续。 CPS 中的“延续”是函数,但 undelimited continuations are not functions.

标签: scheme callcc


【解决方案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 List library 的参考实现,您会发现他们实际上是这样做的。

【讨论】:

    猜你喜欢
    • 2020-07-30
    • 2019-11-15
    • 2013-06-05
    • 2013-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-13
    相关资源
    最近更新 更多