Why doesn't this recur
within mapcat
terminate, whereas the named fn
call version equivalent does?
(def tree [1 [2 [3 5]] [6 [[1 2] [8 [9 10]]]]])
(defn leaves
[node]
(mapcat #(if (vector? %) (leaves %) [%]) node))
(leaves tree)
;; => (1 2 3 5 6 1 2 8 9 10)
(defn leaves-with-recur
[node]
(mapcat #(if (vector? %) (recur %) [%]) node))
(leaves-with-recur tree)
;; Never terminates
If such use of recur
is a straight-forward no-no, is there any reason why the Clojure compiler should not catch this scenario and warn the programmer, or refuse to compile it even? As is the case for non-tail position invocations of recur
for instance.
#(if (vector? %) (recur %) [%])
is a shorthand for
(fn [%]
(if (vector? %)
(recur %)
[%]))
That recur
will recurse to this anonymous function, not to any outer one, and since it doesn't change anything, this is an endless loop.
As for warning—the halting problem is known to be unsolvable, and there is a risk of falling into an endless loop at compile time even when just trying to put some heuristics into place.