local 与 lambda 的惯用用法?

发布于 2024-10-12 20:50:25 字数 762 浏览 1 评论 0原文

HtDP练习30.1.1中,我开始使用 local ,然后将其修改为使用 lambda 来回答这个问题。

(define (add-to-each2 accu a-list)
  (cond
    [(empty? a-list) empty]
    [else (local ((define s (+ accu (first a-list))))
            (cons s (add-to-each2 s (rest a-list))))]))

(define (add-to-each5 accu a-list)
  (cond
    [(empty? a-list) empty]
    [else (cons ((lambda (x y)
                   (first (map + (list (first y))
                               (list x)))) accu a-list)
                (add-to-each5 (+ accu (first a-list))(rest a-list)))]))

这个特定的例子中,对我来说,本地版本更容易阅读。是否存在首选 lambda 版本的情况?谢谢。

In Exercise 30.1.1 of HtDP, I started off using local and then modified it to use lambda in order to answer the question.

(define (add-to-each2 accu a-list)
  (cond
    [(empty? a-list) empty]
    [else (local ((define s (+ accu (first a-list))))
            (cons s (add-to-each2 s (rest a-list))))]))

and

(define (add-to-each5 accu a-list)
  (cond
    [(empty? a-list) empty]
    [else (cons ((lambda (x y)
                   (first (map + (list (first y))
                               (list x)))) accu a-list)
                (add-to-each5 (+ accu (first a-list))(rest a-list)))]))

In this particular instance, to me, the local version is easier to read. Are there situations where the lambda version would be preferred? Thank you.

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

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

发布评论

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

评论(1

吹泡泡o 2024-10-19 20:50:25

首先,我认为您可能会将 relative-2-absoluteadd-to-each 混淆,因为 add-to-each 只是将相同的数字添加到列表的每个元素,而不是递增累加器。本文的其余部分假设情况确实如此,并且只是去掉了增量。

我认为 将是我本地绑定的首选。您的 lambda 示例使用一种通用模式,该模式使用 lambda 和 application 模拟 let

(let ([x e]) body)

相当于:

((lambda (x) body) e)

如果您使用 lambda 的此转换在您的示例中将 更改为 let,您会得到:

(define (add-to-each5 n a-list)
  (cond
    [(empty? a-list) empty]
    [else (cons (let ([x n] [y a-list])
                  (first (map + (list (first y))
                              (list x))))
                (add-to-each5 n (rest a-list)))]))

一个好的编译器可能会为此生成与您的两个示例相同的代码,因此它主要取决于样式。正如您所注意到的,“左-左 lambda”模式可能更难以阅读,所以我更喜欢 let

但是,练习 30.1.1 试图让您使用 map 来替代每个示例中出现的显式递归。您在示例中使用了 map 但一次仅添加一个,这使得 map 有点痛苦:为什么还要费力包装 (list (first y ))(list x) 当你只想要 (+ (first y) x) 时?

让我们看一下 map 的简单定义,看看它对于解决这个问题有何帮助,而不是痛苦:

(define (map f ls)
  (cond
    [(empty? ls) empty]
    [else (cons (f (first ls)) (map f (rest ls)))]))

马上,您应该注意到与 add-to-each 的一些相似之处code>:cond 的第一行检查是否为空,第二行 cons 与递归中的 first 元素有关调用 rest 上的 map。那么,关键是传递 map 一个 f 来对每个元素执行您想要执行的操作。

对于add-to-each,您希望向每个元素添加一个特定的数字。下面是添加 2 的示例:

> (map (lambda (n) (+ 2 n)) (list 1 2 3 4 5))
(3 4 5 6 7)

请注意,maplambda 均作为 30.1.1 请求,并且它们作用于整个列表,而无需原始add-to-each的显式递归:递归全部抽象在map中。

这应该足以让您找到解决方案;不过,我不想透露最终答案:)

First off, I think you might be getting relative-2-absolute confused with add-to-each, since add-to-each just adds the same number to each element of the list, rather than incrementing an accumulator. The rest of this post assumes that's the case, and just takes out that incrementing.

I think let would be my first choice for the local binding. Your lambda example uses a common pattern that simulates let using lambda and application:

(let ([x e]) body)

Is equivalent to:

((lambda (x) body) e)

If you use this transformation from lambda to let in your example, you get:

(define (add-to-each5 n a-list)
  (cond
    [(empty? a-list) empty]
    [else (cons (let ([x n] [y a-list])
                  (first (map + (list (first y))
                              (list x))))
                (add-to-each5 n (rest a-list)))]))

A good compiler will likely generate the same code for this as for your two examples, so it mostly comes down to style. The "left-left lambda" pattern can be more difficult to read, as you note, so I prefer let.

However, Exercise 30.1.1 is trying to make you use map as a replacement for the explicit recursion that occurs in each of your examples. You are using map in your example but only for a single addition at a time, which makes map kind of painful: why bother wrapping up (list (first y)) and (list x) when you just want (+ (first y) x)?

Let's look at a simple definition of map to see how it might be helpful, rather than painful, for this problem:

(define (map f ls)
  (cond
    [(empty? ls) empty]
    [else (cons (f (first ls)) (map f (rest ls)))]))

Right away, you should notice some similarities to add-to-each: the first line of the cond checks for empty, and the second line conses something to do with the first element onto a recursive call to map on the rest. The key, then, is to pass map an f that does what you want to do to each element.

In the case of add-to-each, you want to add a particular number to each element. Here's an example of adding 2:

> (map (lambda (n) (+ 2 n)) (list 1 2 3 4 5))
(3 4 5 6 7)

Notice that map and lambda are both here as 30.1.1 requests, and they act on an entire list without the explicit recursion of the original add-to-each: the recursion is all abstracted away in map.

This should be enough to get you to a solution; I don't want to give away the final answer, though :)

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