Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scheme 在球拍/方案中使用本地_Scheme_Racket_Htdp - Fatal编程技术网

Scheme 在球拍/方案中使用本地

Scheme 在球拍/方案中使用本地,scheme,racket,htdp,Scheme,Racket,Htdp,在中的练习18.1.12中,我使用“local”重新编写了maxi函数 我不知道为什么我会在“现实生活”中这样做,因为这本书的版本似乎更短、更清晰,而且可能更快 (define (maxi alon) (cond [(empty? (rest alon)) (first alon)] [else (cond [(> (first alon) (maxi (rest alon))) (first alon)] [else (maxi (re

在中的练习18.1.12中,我使用“local”重新编写了maxi函数

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

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

这是一个纯粹的教学练习吗?一个有经验的策划师能对上面的代码发表评论吗?谢谢。

就我个人而言,我认为这是一个关于
本地
重要性的糟糕例子,我不相信你完全理解这个问题的重要性,所以我要做的是,先介绍你应该注意的概念,然后再介绍你的例子,最后给你一个更好的例子

概念

首先,local(在许多其他事物中)的概念是澄清代码片段的含义

你的榜样

让我们考虑一下你的例子,你定义了一个局部常量,叫做“代码> M < /Cord>”,这似乎是正确的。尽管如此,由于字母

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如何计算表达式之后),但这不是问题的主要目的


希望这对你有所帮助,而不是使用
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))])]))

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

  (cond
    [(> (first alon) (maxi (rest alon))) (first alon)]
    [else (maxi (rest alon))])
Local会保存结果,因此您不会重复执行相同的工作。请注意,如果使用local将
(maxi(rest alon))
取出,则不再使用else:

(local ((define m (maxi (rest alon))))
  (cond
    [(> (first alon) m) (first alon)]
    [else m]))

好吧,这里有一个问题给你:为什么你认为非本地版本“可能更快”?在听了你的想法后,我会发布这个问题的真实答案。:-)Sifu Chris谢谢你对我的提问。我越来越学会欣赏你的洞察力。因此,当列表变大时,“本地”版本似乎比“纯”递归版本快得多。我是通过调用一个包含20个数字的列表上的时间函数得出这个结论的,我惊讶地发现平均性能相差550倍。不过,我不知道Racket/Scheme内部是如何解释这种差异的。浏览“本地”版本似乎表明,本地函数“m”的20个版本正在产生一个值。感谢Adrian花时间解释清楚!我欠你的债。请注意,教学语言中没有内部定义(故意)。为了强调定义是本地的,必须使用
local
(local ((define m (maxi (rest alon))))
  (cond
    [(> (first alon) m) (first alon)]
    [else m]))