Clojure 序列与传感器有什么关系?
关于序列的两个相关问题: 给定一个传感器,例如Clojure 序列与传感器有什么关系?,clojure,transducer,Clojure,Transducer,关于序列的两个相关问题: 给定一个传感器,例如(def xf(comp(filter odd?)(map inc)) (进入[]xf(范围10))或(进入()xf(范围10))和(序列xf(范围10))之间有什么关系?只是因为没有惰性序列的语法可以用作到的第二个参数,所以我们需要一个单独的函数序列?(我知道,序列还有另一种非传感器用途,将一个集合强制转换成一种或另一种序列。) 上面提到的关于序列的用法 生成的序列元素以增量方式计算。这些序列将根据需要递增地消耗输入,并完全实现中间操作。此行为不同
(def xf(comp(filter odd?)(map inc))
(进入[]xf(范围10))
或(进入()xf(范围10))
和(序列xf(范围10))
之间有什么关系?只是因为没有惰性序列的语法可以用作到
的第二个参数,所以我们需要一个单独的函数序列
?(我知道,序列
还有另一种非传感器用途,将一个集合强制转换成一种或另一种序列。)序列的用法
sequence
没有返回延迟序列,但是sequence
的docstring表示“当提供传感器时,将转换的延迟序列返回到coll(s)中的项,…”,事实上(类(序列xf(范围10)))
返回clojure.lang.LazySeq
。我想我不明白上面Clojure Transformers页面中引用的最后一句话。(序列xform-from)
在传递xform和from的Transformer上创建惰性seq(RT.chunkIteratorSeq)。当请求下一个值时,将对来自的下一个值调用xform(转换的组合)
此行为不同于惰性序列上的等效操作
惰性序列上的等价操作是什么?以您的xf为例,
将过滤奇数?
应用于(范围10)
,生成中间惰性序列,并将映射inc
应用于中间惰性序列,生成最终惰性序列作为结果
我想说,当from是一个不实现IReduceInit的集合时,(into-to-xform-from)
类似于(into-to(sequence-xform-from))
into内部使用(将xform conj转换为from)
执行以下操作:
与(reduce(xform conj)to from)相同
,最后称为clojure.core.protocols/coll-reduce:
(into [] (sequence xf (range 10)))
;[2 4 6 8 10]
(into [] xf (range 10))
;[2 4 6 8 10]
(transduce xf conj [] (range 10))
;[2 4 6 8 10]
(reduce (xf conj) [] (range 10))
;[2 4 6 8 10]
我将您的传感器修改为:
(defn hof-pr
"Prints char c on each invocation of function f within higher order function"
([hof f c]
(hof (fn [e] (print c) (f e))))
([hof f c coll]
(hof (fn [e] (print c) (f e)) coll)))
(def map-inc-pr (partial hof-pr map inc \m))
(def filter-odd-pr (partial hof-pr filter odd? \f))
(def xf (comp (filter-odd-pr) (map-inc-pr)))
这样它就可以在每个转换步骤上打印出字符
在REPL中创建s1,如下所示:
(def s1 (into [] xf (range 10)))
ffmffmffmffmffm
s1被急切地评估(打印f用于过滤,打印m用于映射)。再次请求s1时无评估:
s1
[2 4 6 8 10]
让我们创建s2:
仅对s2中的第一项进行评估。下一个项目将根据要求进行评估:
s2
ffmffmffmffm(2 4 6 8 10)
此外,创建s3,旧方法:
(def s3 (map-inc-pr (filter-odd-pr (range 10))))
s3
ffffffffffmmmmm(2 4 6 8 10)
如您所见,定义s3时没有计算。当请求s3时,将应用筛选10个元素,然后应用其余5个元素的映射,生成最终序列。我发现当前的答案不够清楚,因此
sequence
确实返回一个LazySeq,但它是一个分块的,因此当您在REPL中使用它时,您通常会觉得它很急切,因为您的集合可能太小,分块会使它看起来很急切。我认为块的大小是有点动态的,它并不总是完全相同大小的块,但总的来说,它的大小似乎是32。因此,您的传感器将一次应用于输入采集32个元素,延迟
这是一个简单的传感器,它只需打印减少的元素,并将其原封不动地返回:
(defn printer
[xf]
(fn
([] (xf))
([result] (xf result))
([result input]
(println input)
(xf result input))))
如果我们用它创建一个包含100个元素的序列s
:
(def s
(sequence
printer
(range 100)))
;;> 0
我们看到它打印0
,但没有其他内容。调用sequence
时,第一个元素将从(范围100)
消耗,并将其传递给xf
链进行转换,在本例中,该链只打印它。除第一种元素外,没有其他元素被消耗
现在,如果我们从s
中提取一个元素:
(take 1 s)
;;> 0
;;> 1
;;> 2
;;> 3
;;> 4
;;> 5
;;> 6
;;> 7
;;> 8
;;> 9
;;> 10
;;> 11
;;> 12
;;> 13
;;> 14
;;> 15
;;> 16
;;> 17
;;> 18
;;> 19
;;> 20
;;> 21
;;> 22
;;> 23
;;> 24
;;> 25
;;> 26
;;> 27
;;> 28
;;> 29
;;> 30
;;> 31
;;> 32
我们看到它打印了前32个元素。这是Clojure中分块惰性序列的正常行为。您可以认为它是半懒惰的,因为它一次消耗块大小的元素,而不是一次消耗1个
现在,如果我们尝试获取1到32之间的任何元素,则不会打印任何其他元素,因为前32个元素已被处理:
(take 1 s)
;; => (0)
(take 10 s)
;; => (0 1 2 3 4 5 6 7 8 9)
(take 24 s)
;; => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23)
(take 32 s)
;; => (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)
不打印任何内容,每次获取都返回预期的结果集。我正在使用;=>返回值的代码>和;;>代码>用于打印输出
好的,现在如果我们使用第33个元素,我们希望看到下一块32个元素被打印出来:
(take 33 s)
;;> 33
;;> 34
;;> 35
;;> 36
;;> 37
;;> 38
;;> 39
;;> 40
;;> 41
;;> 42
;;> 43
;;> 44
;;> 45
;;> 46
;;> 47
;;> 48
;;> 49
;;> 50
;;> 51
;;> 52
;;> 53
;;> 54
;;> 55
;;> 56
;;> 57
;;> 58
;;> 59
;;> 60
;;> 61
;;> 62
;;> 63
;;> 64
太棒了!因此,我们再次看到,只取了接下来的32个元素,这使我们现在总共处理了64个元素
这表明,用转换器调用的sequence
实际上创建了一个延迟的分块序列,在该序列中,只有在需要时才会处理元素(一次的分块大小)
这是怎么回事
生成的序列元素以增量方式计算。这些序列将根据需要递增地消耗输入,并完全实现中间操作。此行为不同于惰性序列上的等效操作
这是关于操作发生的顺序。带序列
和传感器:
(sequence (comp A B C) coll)
对于区块中的每个元素,是否会让它们通过:A->B->C
,因此您得到:
A(e1) -> B(e1) -> C(e1)
A(e2) -> B(e2) -> C(e2)
...
A(e32) -> B(e32) -> C(e32)
而对于普通的惰性序列,如:
(->> coll A B C)
将首先让所有分块元素通过A,然后让它们都通过B,然后是C:
A(e1)
A(e2)
...
A(e32)
|
B(e1)
B(e2)
...
B(e32)
|
C(e1)
C(e2)
...
C(e32)
这需要在每个步骤之间进行中间收集,因为A的结果必须收集到一个集合中,然后循环并应用B,等等
我们
A(e1)
A(e2)
...
A(e32)
|
B(e1)
B(e2)
...
B(e32)
|
C(e1)
C(e2)
...
C(e32)
(def s
(sequence
(comp (filter odd?)
printer
(map vector)
printer)
(range 10)))
(take 1 s)
;;> 1
;;> [1]
;;> 3
;;> [3]
;;> 5
;;> [5]
;;> 7
;;> [7]
;;> 9
;;> [9]
(def l
(->> (range 10)
(filter odd?)
(map #(do (println %) %))
(map vector)
(map #(do (println %) %))))
(take 1 l)
;;> 1
;;> 3
;;> 5
;;> 7
;;> 9
;;> [1]
;;> [3]
;;> [5]
;;> [7]
;;> [9]
(def s
(sequence
(comp printer
(filter odd?))
(range 100)))
(take 1 s)
;;> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
(def l
(->> (range 100)
(map #(do (print % "") %))
(filter odd?)))
(take 1 l)
;;> 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31