Clojure中的循环定义问题

3

以下是一个例子:

(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无法解析。
是否有任何解决办法?

2个回答

8

使用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)

我也更喜欢这个词,我会编辑并使用它,谢谢。 - Arthur Ulfeldt
1
在C++中,我的习惯是在头文件的顶部声明所有实体。然后您可以以任何顺序定义它们,无论它们如何相互递归。我看到人们在clojure命名空间中也是这样做的。也许命名空间应该具有语法存在,然后编译器就可以为我们完成它。 - Thumbnail
3
当前采用单遍编译器设计很困难,而双遍编译器难以与宏展开可能产生的副作用等问题协调一致。 - Arthur Ulfeldt

8
如果您只想生成惰性序列,可以使用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 ...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接