Clojure 中的循环定义
Circular definition in Clojure
这是一个例子:
(defn f1 [] (lazy-seq (cons 0 (f2))))
(defn f2 [] (lazy-seq (cons 1 (f3))))
(defn f3 [] (lazy-seq (cons 2 (f1))))
在 Haskell 中,上面示例的等价物会产生 [0, 1, 2, 0, 1, 2, ...] 的延迟序列,但在 clojure 中,这会导致CompilerException 因为无法解析 f2
。
有什么解决办法吗?
使用declare
创建前向声明
user> (declare f1)
#'user/f1
user> (declare f2)
#'user/f2
user> (declare f3)
#'user/f3
或如 Thumbnail 指出的那样:
user> (declare f1 f2 f3)
#'user/f3
同样有效
user> (defn f1 [] (lazy-seq (cons 0 (f2))))
#'user/f1
user> (defn f2 [] (lazy-seq (cons 1 (f3))))
#'user/f2
user> (defn f3 [] (lazy-seq (cons 2 (f1))))
#'user/f3
然后你得到你的递归惰性序列:
user> (take 20 (f3))
(2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0)
如果您只想生成惰性序列,您可以使用 letfn
:
在本地 定义一组相互递归函数
(letfn [(f1 [] (lazy-seq (cons 0 (f2))))
(f2 [] (lazy-seq (cons 1 (f3))))
(f3 [] (lazy-seq (cons 2 (f1))))]
(f1))
=> (0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 ...
这是一个例子:
(defn f1 [] (lazy-seq (cons 0 (f2))))
(defn f2 [] (lazy-seq (cons 1 (f3))))
(defn f3 [] (lazy-seq (cons 2 (f1))))
在 Haskell 中,上面示例的等价物会产生 [0, 1, 2, 0, 1, 2, ...] 的延迟序列,但在 clojure 中,这会导致CompilerException 因为无法解析 f2
。
有什么解决办法吗?
使用declare
创建前向声明
user> (declare f1)
#'user/f1
user> (declare f2)
#'user/f2
user> (declare f3)
#'user/f3
或如 Thumbnail 指出的那样:
user> (declare f1 f2 f3)
#'user/f3
同样有效
user> (defn f1 [] (lazy-seq (cons 0 (f2))))
#'user/f1
user> (defn f2 [] (lazy-seq (cons 1 (f3))))
#'user/f2
user> (defn f3 [] (lazy-seq (cons 2 (f1))))
#'user/f3
然后你得到你的递归惰性序列:
user> (take 20 (f3))
(2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0)
如果您只想生成惰性序列,您可以使用 letfn
:
(letfn [(f1 [] (lazy-seq (cons 0 (f2))))
(f2 [] (lazy-seq (cons 1 (f3))))
(f3 [] (lazy-seq (cons 2 (f1))))]
(f1))
=> (0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2 ...