2013-04-22 69 views
1

我正在使用DrRacket R5RS学习Scheme。我认为我已经掌握了这些概念,但是我无法得到这个简单的递归练习。我认为这是DrRacket中的一个错误,但我不确定。Scheme(DrRacket) - cond语句不适用于递归

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

此代码将产生#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)启动程序时,从1 + 2 + 3!= 5开始返回#F。

现在,这是问题所在。我想做多分支递归。但是,此代码每次都会返回#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

快速回答:用'(else #f)'替换最后一行,它就会起作用。要看到_why_,请看下面的答案。 – 2013-04-22 02:02:58

回答

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。请注意,在方案中,不是#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)替换最后一行它会按预期工作。

+1

你给了我一个更有效的选择。然后,你非常好地解释了我的问题,所以我现在完全明白了为什么发生了。另外,你给了一个修复程序,以便我的应用程序现在可以运行,并且我可以完成其他部分。你真了不起。谢谢! – Birdman 2013-04-22 03:43:49

+0

永远是我的荣幸:) – 2013-04-22 04:03:13