图是不是很懒?
map not quite lazy?
map 似乎并不像我希望的那样懒惰,在此示例中,map 按我的预期调用了一次函数:
(first (map #(do (println "x: " %) %) '(0 1)))
但在这两个示例中,它调用了函数两次:
(first (map #(do (println "x: " %) %) '[0 1]))
(first (map #(do (println "x: " %) %) (doall (range 2))))
选择懒惰与否的基本原则是什么?
有没有办法保证完全懒惰?
感谢您的宝贵时间。
Map(以及处理集合的类似 HOF)处理集合的序列抽象:它从传递的集合 (seq coll)
创建一个序列,然后处理返回的序列。 PersistentList
('(0 1)
是 PersistentList
的实例)通过 ASeq
扩展实现 ISeq
,因此 seq
函数 returns 列表本身.在 PersistentVector
([1 2]
) 的情况下,seq
函数 returns 一个分块序列(性能原因,它一步评估数据块(32 elts),但是 returns只请求元素;当当前块耗尽时计算下一个块。
测试此行为时,尝试使用计数 > 32 的集合进行测试((vec (range 40))
returns 项目 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)。
如果集合是列表,则不使用分块序列,仅评估第一项((apply list (range 40))
returns 项 0-39 的列表):
=> (first (map #(do (println "x: " %) %) (apply list (range 40))))
x: 0
0
map 似乎并不像我希望的那样懒惰,在此示例中,map 按我的预期调用了一次函数:
(first (map #(do (println "x: " %) %) '(0 1)))
但在这两个示例中,它调用了函数两次:
(first (map #(do (println "x: " %) %) '[0 1]))
(first (map #(do (println "x: " %) %) (doall (range 2))))
选择懒惰与否的基本原则是什么?
有没有办法保证完全懒惰?
感谢您的宝贵时间。
Map(以及处理集合的类似 HOF)处理集合的序列抽象:它从传递的集合 (seq coll)
创建一个序列,然后处理返回的序列。 PersistentList
('(0 1)
是 PersistentList
的实例)通过 ASeq
扩展实现 ISeq
,因此 seq
函数 returns 列表本身.在 PersistentVector
([1 2]
) 的情况下,seq
函数 returns 一个分块序列(性能原因,它一步评估数据块(32 elts),但是 returns只请求元素;当当前块耗尽时计算下一个块。
测试此行为时,尝试使用计数 > 32 的集合进行测试((vec (range 40))
returns 项目 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)。
如果集合是列表,则不使用分块序列,仅评估第一项((apply list (range 40))
returns 项 0-39 的列表):
=> (first (map #(do (println "x: " %) %) (apply list (range 40))))
x: 0
0