转换器 halt-when 在与 into 一起使用时引发异常,但在与 sequence 一起使用时不引发。
(sequence (halt-when #{4}) (range)) ;; => (0 1 2 3)
(into [] (halt-when #{4}) (range))
;; class java.lang.Long cannot be cast to class clojure.lang.ITransientCollection (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.ITransientCollection is in unnamed module of loader 'app')
我认为这是由于一个错误造成的,它应返回结果而不是输入,我认为这个实现应该修复这个问题。
(defn halt-when1
([pred] (halt-when1 pred nil))
([pred retf]
(fn [rf]
(fn
([] (rf))
([result]
(if (and (map? result) (contains? result ::halt))
(::halt result)
(rf result)))
([result input]
(if (pred input)
(reduced {::halt (if retf (retf (rf result) input) (rf result))})
(rf result input)))))))
然而,我认为 retf 函数现在与转换器上下文耦合在一起。因此,如果您想转换结果以包含触发停止的输入等,则需要知道在创建转换器时将在特定上下文中使用,并且需要调用 conj、conj! 或其他操作。因此,我认为这个函数签名更有意义。
(defn halt-when2
([pred] (halt-when2 pred nil))
([pred retf]
(fn [rf]
(fn
([] (rf))
([result]
(if (and (map? result) (contains? result ::halt))
(::halt result)
(rf result)))
([result input]
(if (pred input)
(let [r (if retf
(retf rf result input)
result)]
(reduced {::halt (rf r)}))
(rf result input)))))))
这个签名修改了 retf 函数以接受减少函数、结果和输入,现在您可以真正决定要做什么。
(into [] (halt-when2 #{4} (fn [rf r i] (rf r i))) (range)) ;; => [0 1 2 3 4]
也许可以在 halt-when 中添加一个接受选项映射的第三个参数来告诉它我们传入的是 2 个参数的 retf 或 3 个参数的 retf?这有意义吗?或者我可能在请求一个名为 stop-at 的新东西?
--- 编辑 ---
刚刚发现这个,我认为它解释了返回输入背后的更多原因,但我仍然认为提供一个不需要知道实际减少函数是什么的转换结果策略很有用。