全部阅读(除了clojure源代码),有些难以理解传感器如何避免使用中间集合,这应该使它们更加精益和高效。
出现了一个相关的问题,他们是否认为每个输入变换都是独立地应用于其输入的每个元素来自其他元素,如果传感器可能存在限制是通过压缩输入集合上的输入转换来工作 - 逐个元素。
他们是否检查输入函数的代码以确定如何交织它们以使它们产生正确的合成结果?
你能否详细说明在这些方面,clojure中的传感器如何在引擎盖下工作?
答案 0 :(得分:3)
出现了一个相关的问题,即他们是否认为每一个 输入转换应用于其输入的每个元素 独立于其他元素
它们被命名为transducers,因为它们可能具有(隐式)状态。
换能器是一种具有缩小功能并返回缩小功能的功能。
reduce函数是一个需要两个参数的函数:accumulator和item,并返回一个更新的累加器。
这是包含可变状态(如果有的话)的还原函数。
要获得换能器,您必须了解它们两次工作:组合时间然后计算时间。这就是为什么它们是返回函数的函数。
让我们从简单的简化功能开始:conj
。
(map inc)
返回的传感器为(fn [rf] (fn [acc x] (rf acc (inc x))))
。使用conj
调用时,它会返回相当于(fn [acc x] (conj acc (inc x)))
的函数。
(filter odd?)
返回的传感器为(fn [rf] (fn [acc x] (if (odd? x) (rf acc x) acc)))
。使用conj
调用时,它返回等效于(fn [acc x] (if (odd? x) (conj acc x) acc)))
的函数。这个很有意思,因为rf
(下游减少功能有时会被短路)。
如果要将这两个传感器链接起来,只需将(comp (map inc) (filter odd?))
传递给此复合传感器,conj
将成为第一个包裹(filter odd?)
的传感器conj
(因为comp
从右到左应用函数)。然后,生成的filtered-rf
函数将传递给(map inc)
,从而生成一个等于:
(fn [acc x] (filtered-rf acc (inc x)))
其中filtered-rf
为(fn [acc x] (if (odd? x) (conj acc x) acc)))
。如果您内联filtered-rf
,则会获得:(fn [acc x] (let [x+1 (inc x)] (if (odd? x+1) (conj acc x+1) acc)))
。
您可能看不到分配了中间集合或序列。
对于有状态的传感器,除了减少函数具有可变状态(尽可能少并且避免保留其中的所有先前项目)之外,它们是相同的故事:通常是易失性框(参见volatile!
)或可变Java对象。
您可能还注意到,在示例项中首先映射然后过滤:计算从左到右应用,这似乎与comp
相矛盾。这不是:记住comp
这里组成换能器,包裹减少fns的fns。因此,在组合时,包装从右向左(conj
由“过滤rf”包裹然后由“映射rf”包裹)但在计算时,包裹层向内遍历:map,filter然后conj。< / p>
要实现自己的传感器(reduced
,初始化和完成智能化),需要了解详细的实现细节,但总体思路是上面公开的。