3

我正在关注计算机程序的结构和解释,在尝试解决 Ex 1.3 时,我第一次尝试得到以下代码:

(define (sumsq a b c)(
(define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c)))
(define second_h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))

它不起作用,我查找了解决方案并在SICP Wiki上找到了它们

;; ex 1.3
;; implemented using only techniques covered to this point

(define (square x) (* x x))

(define (sum-of-squares x y)
  (+ (square x) (square y)))

(define (largest-two-of-three x y z)
  (if (>= x y)
      (sum-of-squares x (if (>= y z) y z))
      (sum-of-squares y (if (>= x z) x z))))

不同之处在于我使用多个语句来定义变量,然后对平方求和,而正确的方法是将我的每一行定义为函数。

方案一中的函数是线性的吗?还是我错过了整件事?

4

5 回答 5

6

您应该使用适当的缩进和换行来了解您的程序流程。然后,您的第一个提案如下所示:

(定义(sumsq abc)
  ((定义最高
     (如果(>(如果(> ab)ab)
            (如果(> ac)ac))
         (如果 (> ab) ab)
         (如果(> ac)ac)))
   (定义第二个 h
     (如果(>(如果(> ab)ba)
            (如果(> ac)ca))
         (如果(> ab)ba)
         (如果(> ac)ca)))
   (+ (* 最高最高)
      (* second-h second-h)))

首先要注意:括号不匹配;开放的比封闭的多。仔细检查发现第二行的一个左括号是错误的。顺便说一句,这是在您的第一行末尾以某种方式悬空的那个。我冒昧地猜测,当您尝试对此进行评估时,什么都没有发生,因为读者正在等待声明的结尾。

正确的缩进非常重要。我认为 SICP 没有明确解释它,尽管示例通常是这样完成的。我在这里找到了风格指南。

第二个观察:你经常重复自己。在所有这些嵌套if语句中,我不确定你是否真的得到了正确的值。查看您找到的解决方案,了解如何大大简化。

您试图通过给子结果名称来分解复杂性。分解复杂性是好的,但通常最好不要命名结果,而是命名概念。想想你在做什么,然后为这些活动命名。这些是函数,它们构成了您最终几乎可以轻松解决问题的语言。

于 2009-02-02T15:02:19.650 回答
5

你写的(减去一个额外的括号)是:

(define (sumsq a b c)
  (define highest
    (if (> (if (> a b) a b)
           (if (> a c) a c))
      (if (> a b) a b)
      (if (> a c) a c)))
  (define second_h
    (if (> (if (> a b) b a)
           (if (> a c) c a))
      (if (> a b) b a)
      (if (> a c) c a)))
  (+ (* highest highest) (* second_h second_h)))

他们的解决方案将平方和平方和分成单独的函数,但我认为这并不重要。不写(+ (* a a) (* b b)) 会让你不必命名你正在计算的两个值,这会让你在最后把函数写成一个大表达式,但现在有更大的事情要担心。

我认为您遇到的问题是您的 (if.​​..) 表达式太大而难以理解。请注意,有两种模式多次出现:(if (> a b) a b)(if (> a b) b a)。这些是 max 和 min 函数,因此这样定义它们很有用:

(define (min a b) (if (< a b) a b))
(define (max a b) (if (< a b) b a))

这样,您可以将解决方案重写为:

(define (sumsq a b c)
  (define highest
    (if (> (max a b) (max a c))
      (max a b)
      (max a c)))
  (define second_h
    (if (> (min a b) (min a c))
      (min a b)
      (min a c)))
  (+ (* highest highest) (* second_h second_h)))

再次简化它给出:

(define (sumsq a b c)
  (define highest
    (max (max a b) (max a c)))
  (define second_h
    (max (min a b) (min a c)))
  (+ (* highest highest) (* second_h second_h)))

请注意,这种写法更容易推理,(max (max a b) (max a c))显然是a b和的最大值,c实际上可以重写为(max (max a b) c)。但是,看着second_h,并不明显它是正确的。a当三个值中的最小值是什么时会发生什么?

他们在解决方案中使用的技巧是首先比较xy。如果x < y,那么你知道它y不是三个中最小的,所以它要么是最高的,要么是第二高的。您将要使用的另一个数字是 和 中的较高者xz因为这两个中的较小者将是三个中的最小者,您要忽略它。类似的逻辑适用于y < x

于 2009-02-02T15:16:58.093 回答
4

Scheme 的一个想法是bottom-up programming为每个概念操作创建一个函数。这是许多函数式编程语言中推荐的方法。

使用这种方法,您最终会得到许多对参数执行一个逻辑操作的小函数。这样你的代码最终变得更加模块化和干净。

于 2009-02-02T12:05:34.483 回答
4

您的解决方案具有以下形式: (define (func param) (define...) (define...))

但是定义需要这种形式:(define (func param) body)

主体是函数的实现......它做什么,它返回什么。你的身体只是更多的定义,从不做任何事情。这就解释了为什么 Scheme 解释器不接受您的解决方案。

回答“方案函数是单行的吗?”这个问题。您需要调查“开始”表单,如下所示: (begin (+ 1 1) (+ 2 2)) => 4

在上面的例子中,(+ 1 1) 的结果只是被抛出,所以你可以看到 begin 只有当它里面的东西有副作用时才真正有意义。

您应该知道,Scheme 的某些部分(尤其是 let 和 lambda)在它们的主体周围有隐式开始。所以这是有效的:

  (let ((x 1))
    (+ 1 1)
    (+ 2 2))

即使没有开始。这使得代码更容易编写。

最后,当您继续学习 Scheme 时,请始终尝试找到一种没有开始也没有副作用的方法。尤其是在大多数 Scheme 书籍的前几章中,如果你在想,“我想设置那个变量,然后我想做这个,然后这个......”你可能陷入了你的旧编程方式而不是做它是Scheme的方式。副作用完全没有问题,但是大量使用它们意味着您并没有真正按照 Scheme 的最佳工作方式进行编程。

于 2009-02-02T13:39:32.813 回答
1

练习 1.3 要求你定义一个过程,它接受三个数字作为参数并返回两个较大数字的平方和。使用内置的 Scheme 过程squaremax和定义这样的过程很容易min,但是我们在本书中还没有遇到过这些过程,所以我也会定义它们。

(define (square x)
   (* x x))

(define (max x y)
   (if (> x y) x y))

(define (min x y)
   (if (< x y) x y))

(define (sum-of-highest-squares x y z)
   (+ (square (max x y))
      (square (max (min x y) z))))

sum-of-highest-squares过程通过将 x 和 y 的最大值的平方(这两个的最大值从三个中的最小值中消除)和其余两个的最大值的平方(x 和 y 的最小值)相加来工作,这将是第一步留下的任何值)和z。

注意:这是来自我的博客文章SICP 练习 1.1 - 1.5。还有一些链接可以将您带到那里的许多其他 SICP 解决方案。

于 2011-01-18T13:55:16.943 回答