List-Consrehension是否比List-Abstractions更好?

时间:2009-07-24 00:43:45

标签: functional-programming clojure list-comprehension

为什么人们更喜欢像列表这样的列表理解 (for [x '(1 2 3)] (* 2 x))代替(map #(* %1 2) '(1 2 3))

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

5 个答案:

答案 0 :(得分:8)

对于你举的例子,没有任何好处;但一般来说,for在您加入两个(或更多)序列时,或者当您需要进行一些过滤时很有用 - for :let:when通常比嵌套mapfilter的链更具可读性。

答案 1 :(得分:2)

  

列表理解仅仅是   “语法糖”超标   功能性程序,但他们给了一个   直观阅读常见操作   在列表上。 - Guy Lapalme

他们唯一的目的是提高可读性。不要指望使用它们会有任何显着的性能提升。

This论文给出了在Lisp语言中实现List comprehension的一些见解。

答案 2 :(得分:1)

一些一般性的想法

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

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

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

[ (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版本。

答案 3 :(得分:0)

列表推导用于需要以更复杂的方式迭代序列的情况。在你的例子中它们是相同的所以我会重新贴图,因为它更容易阅读。

map cant do 变得丑陋,例如:

(for [x '(1 2 3) y '(3 2 1)] (* 2 x y))

答案 4 :(得分:0)

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