In my answer at Clojure For Comprehension example I have a function that processes its own output:
(defn stream [seed]
(defn helper [slow]
(concat (map #(str (first slow) %) seed) (lazy-seq (helper (rest slow)))))
(declare delayed)
(let [slow (cons "" (lazy-seq delayed))]
(def delayed (helper slow))
delayed))
(take 25 (stream ["a" "b" "c"]))
("a" "b" "c" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc" "aaa" "aab" "aac"
"aba" "abb" "abc" "aca" "acb" "acc" "baa" "bab" "bac" "bba")
It works by creating a forward reference (delayed
) which is used as the second entry in a lazy sequence (slow
). That sequence is passed to the function, which is lazy, and the output from that function (the very first part of the lazy sequence, which does not require the evaluation of delayed
) is then used to set the value of delayed
.
In this way I "tie the knot". But this is done much more elegantly in Haskell (eg. Explanation of “tying the knot”). Given that Clojure has delay
and force
, I wondered if there was a better way to do the above?
The question then: can the (ugly, explicit) mutation (of delayed
) somehow be avoided in the code above? Obviously(?) you still need mutation, but can it be hidden by "lazy" constructs?
[I had a question last night with a similar title when I was still trying to understand how to do this; no one replied before the code above worked, so I deleted it, but I am not really happy with this approach so am trying again.]
See also: Must Clojure circular data structures involve constructs like ref? (kinda frustrating that people are duplicating questions).