Scheme功能是一个内衬吗?

时间:2009-02-02 12:00:49

标签: function scheme sicp

我正在关注计算机程序的结构和解释,在尝试解决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中的函数是否为一个衬里?还是我错过了整件事?

5 个答案:

答案 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 bc的最大值,实际上可以重写为{{ 1}}。但是,看(max (max a b) c),这是不正确的。当second_h是三个值中最小的一个时会发生什么?

他们在解决方案中使用的技巧是首先比较ax。如果y,那么您知道x < y不是三者中最小的,所以它是最高或第二高。您要使用的另一个数字是yx中的较高者,因为这两个中的较低者将是您想要忽略的三个中最小的一个。类似的逻辑适用于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程序squaremaxmin来定义类似的过程很容易,但我们还没有在书中的那一点遇到过这些过程,所以我也定义了它们。

(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解决方案。