我正在关注计算机程序的结构和解释,在尝试解决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))))
不同之处在于我使用多个语句来定义变量然后对方块求和,而正确的方法是将每个行定义为函数。
Scheme中的函数是否为一个衬里?还是我错过了整件事?
答案 0 :(得分:6)
您应该使用正确的缩进和换行符来概述您的程序流程。然后你的第一个提案如下:
(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没有明确解释它,尽管这些例子通常是这样做的。我找到了一个风格指南here。
第二个观察:你重复了很多次。在所有那些嵌套的if
语句中,我不确定你是否真的得到了正确的值。看看你发现的解决方案,看看如何大大简化它。
您尝试通过提供子结果名称来分解复杂性。打破复杂性是好的,但通常更好的是不是结果,而是概念。想想你做了什么,然后命名这些活动。这些是功能,它们构成了你最终几乎无助于解决问题的语言。
答案 1 :(得分:5)
你写的(减去一个额外的paren)是:
(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 (> 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
的最大值,实际上可以重写为{{ 1}}。但是,看(max (max a b) c)
,这是不正确的。当second_h
是三个值中最小的一个时会发生什么?
他们在解决方案中使用的技巧是首先比较a
和x
。如果y
,那么您知道x < y
不是三者中最小的,所以它是最高或第二高。您要使用的另一个数字是y
和x
中的较高者,因为这两个中的较低者将是您想要忽略的三个中最小的一个。类似的逻辑适用于z
。
答案 2 :(得分:4)
Scheme的一个想法是bottom-up programming
,您可以在其中为每个概念操作创建一个函数。这是许多函数式编程语言中推荐的方法。
通过这种方法,您最终会在参数上实现一个逻辑运算的许多小函数。这样你的代码就会变得更加模块化和干净。
答案 3 :(得分:4)
你的解决方案有这样的形式:( define(func param)(define ...)(define ...))
但是定义需要这种形式:(define(func param)body)
正文是函数的实现......它做什么,它返回什么。你的身体只是更多的定义,从不做任何事情。这就解释了为什么您的解决方案不被Scheme解释器接受。
回答问题“方案功能是单行吗?”你需要调查“开始”表格,如下所示:(开始(+ 1 1)(+ 2 2))=&gt; 4
在上面的例子中,(+ 1 1)的结果只是抛出的方式,所以你可以看到,当它内部的东西有副作用时,begin才真正有意义。
你应该知道Scheme的某些部分(特别是let和lambda)隐含在它们的身体周围。所以这是有效的:
(let ((x 1))
(+ 1 1)
(+ 2 2))
即使没有开始。这使代码编写更简单。
最后,当你继续学习Scheme时,总是试图找到一种没有开始和没有副作用的方法。特别是在大多数Scheme书的前几章中,如果你在思考,“我想设置那个变量,那么我想要做到这一点,那么这......”你可能被困在旧的编程方式而不是做它是Scheme方式。副作用完全没有问题,但是大量使用它们意味着你并没有真正以最佳方式编程Scheme。
答案 4 :(得分:1)
练习1.3要求您定义一个过程,该过程将三个数字作为参数,并返回两个较大数字的平方和。使用内置的Scheme程序square
,max
和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 Exercises 1.1 - 1.5。有链接可以带您到那里的许多其他SICP解决方案。