地图不是很懒? [英] map not quite lazy?
问题描述
map似乎不像我想要的那么懒,在此示例中,map一次调用了该函数,就像我期望的那样:
map doesn't seem quite as lazy as I would like, in this example map calls the function one time as I would expect:
(first (map #(do (println "x: " %) %) '(0 1)))
但是在这两个示例中,它两次调用了该函数:
but in these two examples it calls the function two times:
(first (map #(do (println "x: " %) %) '[0 1]))
(first (map #(do (println "x: " %) %) (doall (range 2))))
选择是否懒惰的基本原则是什么?
What is the underlying principle for making the choice to be lazy or not?
有没有办法保证完全懒惰?
Is there a way to guarantee total laziness?
感谢您的时间.
推荐答案
Map(以及对集合起作用的类似HOF)对集合进行序列抽象处理:它从传递的集合(seq coll)
创建一个序列,然后对之后返回序列. PersistentList
('(0 1)
是PersistentList
的实例)通过ASeq
扩展实现ISeq
,因此seq
函数返回列表本身.在PersistentVector
([1 2]
)的情况下,seq
函数返回分块的序列(出于性能原因,它一步一步评估数据块(32个Elts),但仅返回所请求的元素;计算下一个分块当当前块耗尽时).
Map (and similar HOFs that work on collections) works on the sequence abstraction over collections: it creates a sequence from the passed collection (seq coll)
and works on the returned sequence afterwards. PersistentList
('(0 1)
is instance of PersistentList
) implements ISeq
through the ASeq
extension, so seq
function returns the list itself. In case of PersistentVector
([1 2]
), the seq
function returns a chunked sequence (performance reasons, it evaluates chunk (32 elts) of data in one step, but returns only the requested element; the next chunk is calculated when the current chunk is exhausted).
在测试此行为时,请尝试对count> 32的集合进行测试((vec (range 40))
返回项目0-39的向量):
When testing this behaviour, try to test with collections with count > 32 ((vec (range 40))
returns a vector of items 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).
As you can see, the whole chunk (elements 0-31) is evaluated when accessing the first element, the remaining elements (32-39) will be evaluated when requesting the first element from the next chunk.
如果是列表集合,则不使用分块的seq,并且仅评估第一项((apply list (range 40))
返回项目0-39的列表):
In case of collections that are list, chunked seq is not used and only the first item is evaluated ((apply list (range 40))
returns a list of items 0-39):
=> (first (map #(do (println "x: " %) %) (apply list (range 40))))
x: 0
0
这篇关于地图不是很懒?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!