在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可以评论上面的代码吗?谢谢。
答案 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))
两次。
本地保存结果,因此您不会做同样的工作两次。