我正在使用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!
)))
有什么想法吗?
答案 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)
,它将按预期工作。