为什么人们更喜欢像列表这样的列表理解
(for [x '(1 2 3)] (* 2 x))
代替(map #(* %1 2) '(1 2 3))
?
这种编程是否有好处?
1.它更具可读性吗?
2.在某些情况下它更快吗?
3.对于某些类型的操作和数据结构是否更好?
答案 0 :(得分:8)
对于你举的例子,没有任何好处;但一般来说,for
在您加入两个(或更多)序列时,或者当您需要进行一些过滤时很有用 - for
:let
和:when
通常比嵌套map
和filter
的链更具可读性。
答案 1 :(得分:2)
列表理解仅仅是 “语法糖”超标 功能性程序,但他们给了一个 直观阅读常见操作 在列表上。 - Guy Lapalme
他们唯一的目的是提高可读性。不要指望使用它们会有任何显着的性能提升。
This论文给出了在Lisp语言中实现List comprehension的一些见解。
答案 2 :(得分:1)
首先,列表推导只是语法糖,所以除了可读性之外应该没有固有的区别。
但请注意,列表推导实际上统一至少三个高阶函数,即map
,filter
和concatMap
到 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}进行了很好的讨论。函数。