Search code examples
clojure

Loop endlessly on lazy-seq


Why does the second evaluation with butlast loop endlessly in Clojure?

user=> (->> (range) butlast lazy-seq (take 0))
()
user=> (->> (range) butlast lazy-seq first) ; ...

The equivalent in Haskell can be reasonably lazy-eval'ed.

ghci> take 0 . init $ [0..]
[]
ghci> head . init $ [0..]
0

Edit

take 0 is no-op as being pointed out below.


Solution

  • If you look at the implementation of butlast, you can see that it's eager (using loop instead of lazy-seq). An alternate lazy implementation would do what you want:

    (defn butlast'
      "Like clojure.core/butlast but lazy."
      [xs]
      (when (seq xs)
        ((fn f [[x & xs]]
           (if (seq xs)
             (lazy-seq (cons x (f xs)))
             ()))
         xs)))