在Racket / Scheme中使用本地

时间:2010-12-30 07:46:48

标签: scheme racket

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可以评论上面的代码吗?谢谢。

3 个答案:

答案 0 :(得分:3)

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

CONCEPT

首先,本地的想法(在很多其他事情中)是为了澄清代码片段的含义

你的例子

让我们考虑一下你的例子,你定义一个名为m的局部常量,它似乎是正确的。虽然,由于字母m没有重要意义,因此您的解决方案似乎不清楚。那么,我们如何解决您的解决方案?

我们需要为m提供一个名称,明确标识m代表的内容。因此,我们首先直接考虑m代表(maxi (rest alon))

的内容

(maxi (rest alon))只是说找到(rest alon)

的最大数量

因此,我们将m重命名为find-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))]))]))

m替换find-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如何评估表达式之后),但这不是问题的主要目的。

希望这有帮助

答案 1 :(得分:3)

不是使用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))])]))

答案 2 :(得分:1)

在这里使用local更快,因为它每次递归只评估(maxi (rest alon))一次,而对于第二个版本,只要它到达最后一个案例,它就会评估(maxi (rest alon))两次。

本地保存结果,因此您不会做同样的工作两次。