我想知道如何在Clojure中创建一个无限的,不纯的唯一值序列.
(def generator ...) ; def, not defn
(take 4 generator) ; => (1 2 3 4)
(take 4 generator) ; => (5 6 7 8). note the generator's impurity.
Run Code Online (Sandbox Code Playgroud)
我认为这样的设计可能比例如将一个整数值包装到引用类型并从其使用者中增加它更方便,如下所示:
atom)和提供下一个值的具体函数(inc)(take 4 (repeatedly #(swap! _ inc)))我无法想出一个有效的实施方案.有可能吗?
您可以围绕一个不纯的类(如java.util.concurrent.atomic.AtomicLong)包装一个惰性序列来创建一个id序列:
(def id-counter (java.util.concurrent.atomic.AtomicLong.))
(defn id-gen []
(cons
(.getAndIncrement id-counter)
(lazy-seq
(id-gen))))
Run Code Online (Sandbox Code Playgroud)
这样可行,但前提是您不保存序列的头部.如果你创建一个捕获头部的var:
(def id-seq (id-gen))
Run Code Online (Sandbox Code Playgroud)
然后重复调用它,它将从序列的开头返回id,因为你已经抓住了序列的头部:
(take 3 id-seq)
;; => (0 1 2)
(take 3 id-seq)
;; => (0 1 2)
(take 3 id-seq)
;; => (0 1 2)
Run Code Online (Sandbox Code Playgroud)
如果您重新创建序列,由于杂质,您将获得新的值:
(take 3 (id-gen))
;; (3 4 5)
(take 3 (id-gen))
;; (6 7 8)
(take 3 (id-gen))
;; (9 10 11)
Run Code Online (Sandbox Code Playgroud)
我建议您仅出于教育目的(而非生产代码)执行以下操作,但您可以创建自己的ISeq实例,以更直接地实现杂质:
(def custom-seq
(reify clojure.lang.ISeq
(first [this] (.getAndIncrement id-counter))
(next [this] (.getAndIncrement id-counter))
(cons [this thing]
(cons thing this))
(more [this] (cons
(.getAndIncrement id-counter)
this))
(count [this] (throw (RuntimeException. "count: not supported")))
(empty [this] (throw (RuntimeException. "empty: not supported")))
(equiv [this obj] (throw (RuntimeException. "equiv: not supported")))
(seq [this] this)))
(take 3 custom-seq)
;; (12 13 14)
(take 3 custom-seq)
;; (15 16 17)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1051 次 |
| 最近记录: |