Search code examples
clojurelazy-sequencesunfold

Does Clojure have "unfold"?


(defn unfold [step seed]
  (if-let [[val new-seed] (step seed)]
    (cons val (lazy-seq (unfold step new-seed)))
    nil))

Example usage:

(defn fib-step [[x y]] [x [y (+ x y)]])
(take 10 (unfold fib-step [0 1])) ;=> (0 1 1 2 3 5 8 13 21 34)

(defn decreasing [x] (if (neg? x) nil [x (dec x)]))
(unfold decreasing 5) ;=> (5 4 3 2 1 0)

Does this or something like it exist in clojure standard (or commonly used) libs? If not, is there a reason why? The closest I've found is this blog post:

http://www.matlux.net/blog/2014/05/04/anamorphic-adventure-in-clojure


Solution

  • No, unfold is not implemented in Clojure. It is provided by amalloys flatland.useful library, which has wide usage according to CrossClj. Seeing as the blog post you linked provides quite a deep exploration of the subject, I suspect there is more to your question than a direct answer can satisfy... Do you have some scenario in mind where iterate is inadequate? Or disappointed that iterate is not quite unfold in name or behavior?

    (defn fib-step [[a b]] [b (+ a b)])
    (take 10 (map first (iterate fib-step [0 1])))
    
    (take-while (complement neg?) (iterate dec 5))
    

    I prefer to use iterate for these examples because iterate is part of core already. I can see people preferring unfold if that is more familiar to them.

    There are many libraries that provide "things that should have been in core" such as https://weavejester.github.io/medley/medley.core.html. A quick search on https://crossclj.info/ reveals https://github.com/amalloy/useful contains flatland.useful.seq/unfold, which though I have not used looks to be a great implementation by a Clojure core contributor and comes with some other cool stuff to boot.