1

我正在使用 DrRacket R5RS 学习方案。我以为我已经确定了这些概念,但我无法让这个简单的递归练习起作用。我认为这是 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
)))

当我使用 (three '(1 2 3 6) 0 0 0 0) 启动程序时,它返回 #T,因为 1+2+3=6。当我使用 (three '(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!                  
)))

有任何想法吗?

4

1 回答 1

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),它将按预期工作。

于 2013-04-22T01:10:43.527 回答