5

我试图找出如何在使用顶级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返回,否则返回 0。但是,发生的情况是,无论条件的结果如何,过程都将始终返回 0 。testwhenwhen

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

4

4 回答 4

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)))

一些 Scheme 定义了一个名为 let/cc 的宏,它可以让你降低 lambda 的一些噪音:

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

当然,如果您的 Scheme 没有,那么 let/cc 编写起来很简单。


这是有效的,因为 call/cc 将调用它的点保存为延续。它将延续传递给它的函数参数。当函数调用该延续时,Scheme 放弃它迄今为止建立的任何调用堆栈,并从 call/cc 调用的末尾继续。当然,如果函数从不调用延续,那么它只会正常返回。

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


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

于 2010-03-12T18:07:47.040 回答
1

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

于 2010-03-12T16:53:41.703 回答
0

您可以使用“当前继续调用”支持来模拟返回。维基百科上有一个例子。该函数称为call-with-current-continuation,尽管通常有一个别名call/cc是完全相同的。这里还有一个稍微干净一点的例子

注意:这是一种相当先进的 Scheme 编程技术,一开始可能有点费解......!!!!

于 2010-03-12T16:58:34.440 回答
0

在这种情况下,您不想要什么时候,您想要一个如果,尽管不是顶级的。

(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)))

它总是返回零的原因是,无论何时执行的主体,其结果都会掉到地板上。你看,函数定义形式中隐含的 lambda 也创建了一个隐含的开始块,所以

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

begin 的工作方式是它返回内部最后一个表单的结果,同时将所有中间结果放在地板上。这些中间结果旨在产生副作用。您没有使用任何这些,这很好(!),但您必须小心在函数定义中只有一种形式(您真正想要的结果)。

格雷姆

于 2010-03-12T22:04:05.473 回答