模仿Python产量的惯用Clojure方法 [英] Idiomatic Clojure way of mimicking Python's yield

查看:73
本文介绍了模仿Python产量的惯用Clojure方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在遍历列表,逐步建立状态,偶尔遇到某个哨兵时,我会返回结果。如果我在Python中执行此操作,则会懒惰地 yield 结果,并在执行过程中跟踪函数本地范围内的状态:

I'm iterating through a list, building up state as I go, and occasionally when I encounter a certain sentinel, I return a result. If I was doing this in Python, I would lazily yield the results, tracking state in the function's local scope as I go:

# this is simplified for illustration
def yielder(input_list):
    state = 0
    for item in input_list:
        if item = 'SENTINEL':
            yield state * 2
            state = 0
        else:
            state += item

yielder([1, 5, 2, 5, 'SENTINEL', 4, 6, 7]) # [26, 34]

我的第一个实现使用 reduce ,但是不如 yield 那样好,因为:

My first implementation uses reduce, but that's not as good as yield because:


  • 我在两次迭代之间传递的值既具有循环状态,又具有要产生的项,这似乎很笨拙


iterate 可用于减轻后者,但我不愿意实际上想为每个输入项返回一些内容,因此将需要更多操作。

iterate could be used to mitigate the latter, but i don't actually want to return something for every input item, so it would require more munging.

在Clojure中执行此操作的惯用方式是什么?

推荐答案

您可以构建这可以使用您提到的lazy-seq来解决,也可以使用 partition reduce 将问题分为多个阶段,然后进行线程化他们在一起。我将使用thread-last宏单独显示每个步骤:

You can build this yourself using lazy-seq as you mention or you could use partition and reduce to split the problem into phases then thread them together. I'll use the thread-last macro to show each step on it's own:

user> (->> [1, 5, 2, 5, :SENTINEL, 4, 6, 7] ;; start with data
           (partition-by #(= :SENTINEL %))  ;; ((1 5 2 5) (:SENTINEL) (4 6 7))
           (take-nth 2)                     ;; ((1 5 2 5) (4 6 7))
           (map #(* 2 (reduce + %))))       ;; the map here keeps it lazy
(26 34)

,这里是usin lazy-直接seq:

and here it is usin lazy-seq directly:

user>  (defn x [items]
         (when (seq items)
           (lazy-seq (cons (* 2 (reduce + (take-while #(not= :SENTINEL %) items)))
                           (x (rest (drop-while #(not= :SENTINEL %) items)))))))
#'user/x
user> (x [1, 5, 2, 5, :SENTINEL, 4, 6, 7])
(26 34)

这篇关于模仿Python产量的惯用Clojure方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆