方案早期“短路回归”?

时间:2010-03-12 16:50:59

标签: scheme continuations short-circuiting

我试图找出如何使用顶级ifcond类似构造在方案程序中使用进行“早期返回”。

(define (win b)
 (let* ((test (first (first b)))
        (result (every (lambda (i) (= (list-ref (list-ref b i) i) test))
                       (enumerate (length b)))))
  (when (and (not (= test 0)) result) test))
 0)

例如,在上面的代码中,如果满足win条件,我希望test返回when,否则返回0.但是,会发生的情况是该过程将<无论when条件的结果如何,em>总是返回0。

我以这种方式构造代码的原因是因为在这个过程中我需要做很多复杂的检查(类似于示例中的let*的多个块)并将所有内容放在一个大的cond中会非常笨拙。

4 个答案:

答案 0 :(得分:7)

以下是如何使用call / cc自行构建return

(define (example x)
  (call/cc (lambda (return)
    (when (< x 0) (return #f))
    ; more code, including possible more calls to return
    0)))

某些方案定义了一个名为let / cc的宏,它可以让你删除lambda的一些噪音:

(define (example x)
  (let/cc return
    (when (< x 0) (return #f))
    0))

当然,如果你的计划没有,那么让/ cc写起来是微不足道的。


这是有效的,因为call / cc保存了它被称为延续的点。它将该延续传递给它的函数参数。当函数调用该延续时,Scheme放弃它到目前为止构建的任何调用堆栈,并从call / cc调用结束继续。当然,如果函数从不调用continuation,那么它只是正常返回。

直到你开始从该函数返回它们,或者可能将它们存储在全局数据结构中并稍后调用它们之前,Continuations不会真正令人费解。否则,它们就像任何其他语言的结构化goto语句一样(而/ for / break / return / continue / exceptions / conditions)。


我不知道您的完整代码是什么样的,但是最好使用cond并将复杂的检查分解为单独的函数。需要returnlet*通常是过于强制性的代码的症状。但是,call / cc方法现在应该让你的代码正常工作。

答案 1 :(得分:1)

一种方法是使用递归而不是循环,然后通过不再进一步递归来实现提前退出。

答案 2 :(得分:0)

您可以使用“使用当前继续调用”支持来模拟返回。 wikipedia上有一个例子。该功能称为 call-with-current-continuation ,虽然通常有一个名为 call / cc 的别名,但这完全相同。还有一个稍微清晰的例子here

注意:这是一种非常先进的Scheme编程技术,起初可能有点弯曲...... !!!!

答案 3 :(得分:0)

在这种情况下,你不想要一个if,你想要一个if,尽管不是顶级。

(define (win b)
  (let* ((test (first (first b)))
         (result (every (lambda (i) (= (list-ref (list-ref b i) i) test))
                        (enumerate (length b)))))
    (if (and (not (= test 0)) result) 
        test
        0)))

它总是返回零的原因是,无论是什么时候被执行,它的结果都会被丢弃在地板上。你看,函数define form中隐含的lambda也创建了一个隐式的开始块,所以

(define foo 
  (lambda (b)
     (begin
       (let ...)
       0)))

并且开始工作的方式是它返回最后一个表单的结果,同时将所有中间结果丢弃在地板上。这些中间结果旨在产生副作用。你没有使用任何一个,这很棒(!),但你必须小心,在函数定义中只有一个表单(你真正想要的结果)。

GREM