Scheme(DrRacket) - cond语句不适用于递归

时间:2013-04-22 00:57:11

标签: scheme racket

我正在使用DrRacket R5RS学习Scheme。我认为我正在理解这些概念,但我无法通过这种简单的递归练习来实现。我认为这是DrRacket中的一个错误,但我不确定。

有人能看到问题,并希望解释为什么我的代码不起作用?我真的想学习这种功能语言。

此代码将正确生成#T和#F:

(define three (lambda (L target1 target2 target3 sum)
    (cond
        ((= target1 0) (three L (car L) (cadr L) (caddr L) 0))
        ((NULL? L) (= (- sum (+ target1 (+ target2 target3))) (+ target1 (+ target2 target3))))  ; sum minus targets = targets
        (else (three (cdr L) target1 target2 target3 (+ sum (car L))))       ; return true if branch returns true
)))

当我用(3'(1 2 3 6)0 0 0 0)启动程序时,它返回#T,因为1 + 2 + 3 = 6。当我用(3'(1 2 3 5)0 0 0 0)启动程序时,它返回#F,因为1 + 2 + 3!= 5.

现在,这是问题所在。我想做多分支递归。但是,这段代码每次都会返回#T!因为我无法让它返回#F,所以我无法跳到递归的下一个分支。

(define three (lambda (L target1 target2 target3 sum)
    (cond
        ((= target1 0) (three L (car L) (cadr L) (caddr L) 0))
        ((NULL? L) (= (- sum (+ target1 (+ target2 target3))) (+ target1 (+ target2 target3))))  ; sum minus targets = targets
        ((three (cdr L) target1 target2 target3 (+ sum (car L))) #T)       ; return true if branch returns true                  
        (else 'hit_the_bottom)  ; IT NEVER HITS THIS STATEMENT!                  
)))

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

解决方案太复杂了,如果你只想检查列表中前三个数字的总和是否等于第四个数字,一个更简单的非递归方法会更好:

(define (three lst)
  (= (+ (first lst) (second lst) (third lst))
     (fourth lst)))

除此之外,你为什么不坚持第一种方法呢?它对您有用,并且不清楚“多分支递归”是什么意思,为什么第二种方法有必要 - 不是第一种方法“多分支”?毕竟,它已经递归地在两个部分中调用three。关于第二种方法总是返回#t的原因 - 这一行:

(else 'hit_the_bottom)

...确实会被执行,但因为它是递归调用的一部分,它将返回到这一行:

((three (cdr L) target1 target2 target3 (+ sum (car L))) #t)

'hit_the_bottom#t,因此整个过程最终会返回#t。请注意,在Scheme 中,#f的所有都是#t,特别是在这种情况下,'hit_the_bottom将被解释为#t。为了清楚else部分真正被执行,运行此代码,您将在屏幕上看到'hit_the_bottom一次:

(define three
  (lambda (L target1 target2 target3 sum)
    (cond ((= target1 0)
           (three L (car L) (cadr L) (caddr L) 0))
          ((null? L)
           (= (- sum (+ target1 target2 target3))
              (+ target1 target2 target3)))
          ((three (cdr L) target1 target2 target3 (+ sum (car L)))
           #t)
          (else (display 'hit_the_bottom) 'hit_the_bottom))))

(three '(1 2 3 6) 0 0 0 0)
=> #t
(three '(1 2 3 5) 0 0 0 0)
=> hit_the_bottom #t

最后,要更正第二种方法,请将最后一行替换为(else #f),它将按预期工作。