6

在 htdp 的练习 18.1.12 中我使用“local”重写了 maxi 函数。

;; maxi : non-empty-lon  ->  number
;; to determine the largest number on alon
(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (local ((define m (maxi (rest alon))))
            (cond
              [(> (first alon) m) (first alon)]
              [(> m (first (rest alon))) m]
              [else (first (rest alon))]))]))

我不确定为什么我会在“现实生活”中这样做,因为这本书的版本似乎更短、更清晰,而且可能也更快。

(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (cond
        [(> (first alon) (maxi (rest alon))) (first alon)]
        [else (maxi (rest alon))])]))

它是否意味着纯粹的教学练习?有经验的 Schemer 可以评论上面的代码吗?谢谢你。

4

3 回答 3

4

除了使用local,还可以使用 Racket 的内部定义(尤其是更新的版本)。

例如:

(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (define m (maxi (rest alon)))        ; here is an internal define
          (cond
            [(> (first alon) m) (first alon)]
            [(> m (first (rest alon))) m]
            [else (first (rest alon))])]))
于 2011-09-25T04:36:39.587 回答
4

就个人而言,我认为这是一个很差的例子,local我不相信你完全理解这个问题的重要性,所以我要做的是通过你应该注意的概念,然后通过你的例子,最后给你一个更好的例子。

概念

首先,这里的本地概念(除其他外)是为了阐明代码片段的含义

你的榜样

让我们考虑您的示例,您定义了一个名为的局部常量m,它看起来是正确的。虽然,由于这封信m没有重要意义,您的解决方案似乎还不清楚。那么,我们如何解决您的解决方案?

我们需要给出m一个清楚地识别m代表什么的名称。所以,我们首先直接考虑什么m代表什么(maxi (rest alon))

那么(maxi (rest alon))简单地说找到最大数量(rest alon)

所以让我们重命名mfind-max

现在您的代码如下所示:

;; maxi : non-empty-lon  ->  number
;; to determine the largest number on alon
(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (local ((define find-max (maxi (rest alon))))
            (cond
              [(> (first alon) find-max) (first alon)]
              [(> find-max (first (rest alon))) find-max]
              [else (first (rest alon))]))]))

替换mfind-max使代码更清晰!给我们一个经验法则,给你的常量起有意义的名字。

我的例子

为了进一步阐明,让我们考虑一个函数,它消耗两个点并产生通过连接两个点创建的线段的斜率。我们的第一种方法可能是:

;;where x1,y1 belong to point 1 and x2,y2 belong to point 2
(define (find-slope x1 y1 x2 y2)
  (sqrt (+ (sqr (- x2 x1))) (sqr (- y2 y1))))

但我们可以更清楚地使用local

(define (find-slope x1 y1 x2 y2)
  (local
    [(define delta-x (- x2 x1))
     (define delta-y (- y2 y1))]
    (sqrt (+ (sqr delta-x)) (sqr delta-y))))

注意 delta 如何描述函数在该部分的作用;找出 x 或 y 的变化。所以,我们需要在这里学习的是,虽然第一个解决方案可能使用较少的代码,但第二个解决方案描述了我们正在做的事情并且可以轻松阅读。这就是问题的全部想法,它可能看起来很愚蠢,但这是他们在学术环境中学习计划时倾向于强调的惯例。

至于第一个和第二个解决方案的效率,由于显而易见的原因,第二个解决方案肯定要快得多(在您查看 Racket 如何评估表达式之后),但这不是问题的主要目的。

希望这可以帮助

于 2011-01-02T07:04:40.820 回答
2

在这里使用 local 要快得多,因为它(maxi (rest alon))每次递归只计算一次,而在第二个版本中,(maxi (rest alon))它在到达最后一种情况时会计算两次:

  (cond
    [(> (first alon) (maxi (rest alon))) (first alon)]
    [else (maxi (rest alon))])

本地保存结果,因此您不会重复执行相同的工作。请注意,如果您(maxi (rest alon))使用 local 解除,则不再是 else 情况:

(local ((define m (maxi (rest alon))))
  (cond
    [(> (first alon) m) (first alon)]
    [else m]))
于 2015-11-30T22:08:03.517 回答