3

我刚刚开始研究 SICP,我正在做第一个问题集,即练习 1.3:“定义一个以三个数字作为参数并返回两个较大数字的平方和的过程。”

(define (toptwosq x y z)
  (cond ((and (> x y) (> z y))) (+ (* x x) (* z z))
        ((and (> y x) (> z x))) (+ (* y y) (* z z))
        ((and (> x z) (> y z))) (+ (* x x) (* y y))))

当我运行它时,我得到了非常奇怪的结果(没有一个让我得到最大两个数字的平方和)。我找到了其他可行的解决方案,并且我理解它们为什么会起作用……但是为什么我的不起作用?

4

3 回答 3

4

cond过早地关闭条款。

((and (> xy) (> zy))) 是您的第一个cond子句,如果为真则返回#t,否则返回#f,如果为真,则将值cond设为#t。

(+ (* xx) (* zz)) 是您的第二个cond子句,它将始终返回 x 的平方和 z 的平方之和的值,使cond语句返回该值作为 #f 以外的任何值考虑和真实。有时利用这个单部分子句很有用,但大多数时候你想使用两部分子句。

(define (toptwosq x y z)
  (cond ((and (> x y) (> z y)) (+ (* x x) (* z z)))
        ((and (> y x) (> z x)) (+ (* y y) (* z z)))
        ((and (> x z) (> y z)) (+ (* x x) (* y y)))))

你真的应该有一个else条款

(else (+ (square x) (square y)) 

因为到目前为止,您提出的所有案例都不会发现 xy 和 z 值相同的情况。

获得一个进行括号匹配的编辑器,你的生活会变得更轻松。

于 2013-07-23T00:41:37.883 回答
3

正如@WorBlux 指出的那样,您有一些括号问题。除此之外,我有几个提示:

  • 如果使用嵌套if的s来分隔条件会更清楚一些
  • 您的条件不正确,缺少相等的情况
  • 如果条件合适,就不需要一个包罗万象的else案例
  • 您应该声明一个帮助程序来执行实际的平方和

这就是我的意思:

(define (sumsq x y)
  (+ (* x x) (* y y)))

(define (toptwosq a b c)
  (if (>= a b)
      (if (>= b c)
          (sumsq a b)
          (sumsq a c))
      (if (>= a c)
          (sumsq b a)
          (sumsq b c))))

相同的代码可以使用 编写如下cond,注意如何正确表达条件以覆盖所有情况:

(define (toptwosq a b c)
  (cond ((and (>= a b) (>= b c)) (sumsq a b))
        ((and (>= a b) (<  b c)) (sumsq a c))
        ((and (<  a b) (>= a c)) (sumsq b a))
        ((and (<  a b) (<  a c)) (sumsq b c))))

最后一个条件可以替换为else. 这不是“包罗万象”,我们确信在这一点上没有更多的案例需要考虑:

(define (toptwosq a b c)
  (cond ((and (>= a b) (>= b c)) (sumsq a b))
        ((and (>= a b) (<  b c)) (sumsq a c))
        ((and (<  a b) (>= a c)) (sumsq b a))
        (else                    (sumsq b c))))

最后,如果我们很聪明,我们可以摆脱一种情况(第一种和第三种情况相同)并进一步简化条件:

(define (toptwosq a b c)
  (cond ((or (>= a b c) (and (>= a c) (> b a)))
         (sumsq a b))
        ((and (>= a b) (> c b))
         (sumsq a c))
        (else (sumsq b c))))
于 2013-07-23T01:15:46.413 回答
0

顺便说一句,这就是解决方案代码可以从更高阶描述中导出的方式。

使用等式语法,(读$作“of”;f x表示应用,括号仅用于分组)

sum_sqrs_of_biggest_two (a,b,c) =                -- three arguments

      = sumsqrs $ take 2 $ sort [a,b,c]          -- list of three values
      = sumsqrs $ take 2 $ merge (sort [a,b]) [c]
      = sumsqrs $ take 2 $ 
          if a >= b
            then merge [a,b] [c]
            else merge [b,a] [c]
      = sumsqrs $
          if a >= b 
            then if b >= c then [a,b] else [a,c]
            else if a >= c then [b,a] else [b,c]
      = if a >= b 
            then if b >= c then a^2+b^2 else a^2+c^2
            else if a >= c then a^2+b^2 else b^2+c^2

...并将其转换回 Scheme 语法。

于 2013-07-23T18:59:31.550 回答