local 与 lambda 的惯用用法?
在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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
首先,我认为您可能会将
relative-2-absolute
与add-to-each
混淆,因为add-to-each
只是将相同的数字添加到列表的每个元素,而不是递增累加器。本文的其余部分假设情况确实如此,并且只是去掉了增量。我认为
让
将是我本地绑定的首选。您的 lambda 示例使用一种通用模式,该模式使用 lambda 和 application 模拟let
:相当于:
如果您使用 lambda 的此转换在您的示例中将 更改为
let
,您会得到:一个好的编译器可能会为此生成与您的两个示例相同的代码,因此它主要取决于样式。正如您所注意到的,“左-左
lambda
”模式可能更难以阅读,所以我更喜欢let
。但是,练习 30.1.1 试图让您使用
map
来替代每个示例中出现的显式递归。您在示例中使用了map
但一次仅添加一个,这使得map
有点痛苦:为什么还要费力包装(list (first y ))
和(list x)
当你只想要(+ (first y) x)
时?让我们看一下
map
的简单定义,看看它对于解决这个问题有何帮助,而不是痛苦:马上,您应该注意到与
add-to-each
的一些相似之处code>:cond
的第一行检查是否为空,第二行cons
与递归中的first
元素有关调用rest
上的map
。那么,关键是传递map
一个f
来对每个元素执行您想要执行的操作。对于
add-to-each
,您希望向每个元素添加一个特定的数字。下面是添加2
的示例:请注意,
map
和lambda
均作为 30.1.1 请求,并且它们作用于整个列表,而无需原始add-to-each
的显式递归:递归全部抽象在map
中。这应该足以让您找到解决方案;不过,我不想透露最终答案:)
First off, I think you might be getting
relative-2-absolute
confused withadd-to-each
, sinceadd-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. Yourlambda
example uses a common pattern that simulateslet
usinglambda
and application:Is equivalent to:
If you use this transformation from
lambda
tolet
in your example, you get: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 preferlet
.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 usingmap
in your example but only for a single addition at a time, which makesmap
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:Right away, you should notice some similarities to
add-to-each
: the first line of thecond
checks for empty, and the second linecons
es something to do with thefirst
element onto a recursive call tomap
on therest
. The key, then, is to passmap
anf
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 adding2
:Notice that
map
andlambda
are both here as 30.1.1 requests, and they act on an entire list without the explicit recursion of the originaladd-to-each
: the recursion is all abstracted away inmap
.This should be enough to get you to a solution; I don't want to give away the final answer, though :)