地图似乎并不像我想的那样懒,在这个示例中,地图按照我的预期调用函数一次:
(first (map #(do (println "x: " %) %) '(0 1)))
但在这两个例子中,它调用了两次函数:
(first (map #(do (println "x: " %) %) '[0 1]))
(first (map #(do (println "x: " %) %) (doall (range 2))))
选择是否懒惰的基本原则是什么?
有没有办法保证完全懒惰?
感谢您的时间。
答案 0 :(得分:4)
Map(以及处理集合的类似HOF)处理集合上的序列抽象:它从传递的集合(seq coll)
创建一个序列,然后处理返回的序列。 PersistentList
('(0 1)
是PersistentList
的实例)通过ISeq
扩展名实现ASeq
,因此seq
函数会返回列表本身。在PersistentVector
([1 2]
)的情况下,seq
函数返回一个分块序列(性能原因,它在一个步骤中评估数据的块(32个),但只返回请求的元素;当前块耗尽时计算下一个块。)
测试此行为时,尝试使用count>进行集合测试32((vec (range 40))
返回项目0-39的向量):
=> (first (map #(do (println "x: " %) %) (vec (range 40))))
x: 0
x: 1
x: 2
x: 3
...
x: 30
x: 31
0
如您所见,在访问第一个元素时会计算整个块(元素0-31),在从下一个块请求第一个元素时将评估其余元素(32-39)。
如果集合是列表,则不使用chunked seq,只评估第一个项目((apply list (range 40))
返回项目列表0-39):
=> (first (map #(do (println "x: " %) %) (apply list (range 40))))
x: 0
0