4

为什么人们更喜欢列表推导式
(for [x '(1 2 3)] (* 2 x))而不是 (map #(* %1 2) '(1 2 3))?

这种编程有什么好处吗?
1. 是否更具可读性?
2. 在某些情况下会更快吗?3. 对于某些类型的操作和数据结构是否更好?

4

5 回答 5

8

对于您给出的示例,没有任何好处;但总的来说,for当您连接两个(或更多)序列时,或者当您需要进行一些过滤时,它很有用 - forwith :letand:when通常比嵌套的链更具可读性mapand filter

于 2009-07-24T00:48:59.720 回答
2

列表推导只是标准函数程序的“语法糖”,但它们可以直观地阅读列表上的常见操作。——盖伊·拉帕尔梅

他们唯一的目的是更好的可读性。不要期望通过使用它们来显着提高性能。

本文对在类似 Lisp 的语言中实现列表推导提供了一些见解。

于 2009-08-07T06:00:58.797 回答
1

一些一般的想法

首先,列表推导式只是语法糖,所以除了可读性之外应该没有内在的区别。

但请注意,列表推导式实际上将至少三个高阶函数,即,和统一一种语法。因此,在需要这些复杂组合的重要情况下,语法可以具有很大的可读性优势。mapfilterconcatMap

除此之外,可以方便地使用值绑定来存储结果并使事情更加清晰:

[ (x, y) | x <- [1..10],
           y <- [1..10], 
           let dist = (x - 5)² + (y - 5)²,
           dist < 10² ]

但无论如何,列表推导可以比仅仅处理列表更通用。基本上,他们可以Monad使用统一且方便的语法处理任何内容。例如,F# 甚至将其扩展到控制任意程序流。

其次,比通常的高阶函数更抽象,列表推导实际上可以更快,因为编译器可以利用优化法则,否则将由程序员考虑。

[ x + 1 | x <- numbers, even x ]

直接的翻译是

map (\x -> x + 1) (filter even x)

列表被迭代两次,产生一个毫无价值的中间结果。

然而,编译器可以识别和优化上述模式并生成直接的优化filterMap版本。

于 2010-12-26T17:08:30.210 回答
0

列表推导式用于需要以更复杂的方式遍历序列的情况。在您的示例中,它们是相同的,因此我会推荐地图,因为它更易于阅读。

地图不能因为这样做而变得丑陋,例如:

(for [x '(1 2 3) y '(3 2 1)] (* 2 x y))
于 2009-07-24T00:50:43.510 回答
0

for我知道这是一个 Clojure 问题,但 Martin Odersky 等人的“Scala 编程”一书对理解如何映射到mapfilter函数进行了很好的讨论。

于 2010-12-26T15:10:48.690 回答