在球拍/方案中使用本地

发布于 2024-10-09 13:26:38 字数 860 浏览 7 评论 0原文

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

In Exercise 18.1.12 from htdp, I've re-written the maxi function using "local".

;; 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))]))]))

I'm not sure why I would do this in "real life" as it seems the book's version is shorter, clearer and probably faster as well.

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

Was it meant to be a purely pedagogical exercise? Could an experienced Schemer comment on the code above? Thank you.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

拔了角的鹿 2024-10-16 13:26:38

就我个人而言,我认为这是一个很糟糕的例子来说明本地的重要性,并且我不相信您完全理解这个问题的重要性,所以我要做的是回顾一下您应该注意到的概念,然后检查你的例子,最后给你一个更好的例子。

概念

首先,这里的本地概念(以及许多其他事物)是为了澄清代码片段的含义

您的示例

让我们考虑一下您的示例,您定义了一个名为 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< /code> 加上 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 如何计算表达式之后),但这不是问题的主要目的。

希望这有帮助

Personally, I think this is a poor example of the importance of local and I don't believe you fully understood the importance of the question, so what I will do is go through the concept that you should notice, then go through your example and finally give you a better example.

CONCEPT

First off, the idea of local here (among many other things) is to clarify the meaning of snippets of code.

YOUR EXAMPLE

Lets consider your example, you define a local constant called m which appears to be correct. Although, since the letter m has no significant meaning your solution appears to be unclear. So, how might we fix your solution?

We need to give m a name that clearly identifies what m represents. So, we begin by directly considering what m represents which is (maxi (rest alon))

Well (maxi (rest alon)) simply says find the maximum number of (rest alon)

So lets rename m to find-max

Now your code looks like:

;; 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))]))]))

Replacing m with find-max makes the code much clearer! Leaving us with a rule of thumb, give your constants meaningful names.

MY EXAMPLE

To further clarify, lets consider a function that consumes two points and produces the slope of the line segment created by connecting the two points. Our first approach might be:

;;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))))

But we could be clearer using 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))))

Notice how delta describes what the function does at that part; finding the change in x or y. So, what we need to learn here is that, although the first solution may make use of less code, the second solution describes what we are doing and can be easily read. That was the entire idea of the question and it may seem stupid, but it is a convention they tend to stress when learning scheme in an academic setting.

As for the efficiency of the first and second solution, the second solution is definitely much faster for obvious reasons (after you look at how Racket evaluates expressions), but that wasn't the main purpose of the question.

Hope this helps

背叛残局 2024-10-16 13:26:38

除了使用 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))])]))

Instead of using local, one can go as well using Racket's internal definitions (especially with more recent versions).

For example:

(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))])]))
笨死的猪 2024-10-16 13:26:38

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

Using local is way faster here because it only evaluates (maxi (rest alon)) once per recursion, whereas with the second version it evaluates (maxi (rest alon)) twice whenever it gets to the last case:

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

Local saves the result so you don't do the same work twice. Notice if you lift the (maxi (rest alon)) out with local, it isn't in the else case anymore:

(local ((define m (maxi (rest alon))))
  (cond
    [(> (first alon) m) (first alon)]
    [else m]))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文