3

Here is an example:

(defn f1 [] (lazy-seq (cons 0 (f2))))
(defn f2 [] (lazy-seq (cons 1 (f3))))
(defn f3 [] (lazy-seq (cons 2 (f1))))

In Haskell, the equivalent of the above example would produce a lazy sequence of [0, 1, 2, 0, 1, 2, ...], but in clojure this would lead to a CompilerException because f2 could not be resolved.

Is there any way around this?

qed
  • 22,298
  • 21
  • 125
  • 196
  • possible duplicate of [Must Clojure circular data structures involve constructs like ref?](http://stackoverflow.com/questions/11568036/must-clojure-circular-data-structures-involve-constructs-like-ref) – galdre Apr 17 '15 at 23:39

2 Answers2

8

use declare to create forward declarations

user> (declare f1) 
#'user/f1
user> (declare f2)
#'user/f2
user> (declare f3)
#'user/f3

or as Thumbnail points out:

user> (declare f1 f2 f3)
#'user/f3

works as well

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

then you get your recursive lazy sequence:

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
  • 90,827
  • 27
  • 201
  • 284
  • neet I like that better as well, I'll edit to use that instead, thanks – Arthur Ulfeldt Apr 17 '15 at 21:21
  • 1
    It was my habit with C++ to declare *all* the entities at the top of the header file. Then you can define them in any order you like, however mutually recursive they are. I see people doing the same with clojure namespaces. Perhaps a namespace should have a syntactic presence, then the compiler could do it for us. – Thumbnail Apr 17 '15 at 22:56
  • 3
    It's tough with the current one-pass compiler design, and a two pass compiler is hard to reconcile with the possibility of side-effecting macro expansion, amongst other issues – Arthur Ulfeldt Apr 18 '15 at 00:05
8

If you just want to produce the lazy sequence, you can define a bunch of mutually recursive functions locally using 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 ...
Thumbnail
  • 13,293
  • 2
  • 29
  • 37