I'm having trouble finding the answer to this in the Clojure docs. I'm new to Clojure and it seems as though you can use recur
in two different ways and essentially get the same result.
Example 1:
(defn my-function [num]
(if (> num 10)
num
(recur (+ num 1))))
Example 2:
(defn my-function [num]
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1)))))
From what I can tell, these two forms seem to do the exact same thing. I understand that the reason recur
is good generally is that under the right circumstances the compiler can hack together some kind of pseudo-tail-call-optimization, which I really like and would love to make use of as often as possible. So here are my questions:
loop
when recur
seems to work without it?loop
just create a "recursion scope" kind of like how let
creates a mini scope?loop
?Just to answer your questions one by one:
loop
allows you to accept and pass arbitrary parameters. Without loop
you would be limited with only being able to pass only what function accepts. It would lead to heaps of tiny auxiliary functions
Yep, kind of
It must be a tail call and it's constrained by compiler
loop
. You can always replace it
with a call to an anonymous fn
form. loop
acts as a let
that doubles as a recursion point for
recur
. If a loop
catches no recur
s, you can replace it with a
let
, and vice versa.recur
that implements tail recursion (and only tail
recursion), whether it recurs to a loop
or a fn
form.To illustrate (1), you can replace the loop
form in example 2
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1))))
... with
((fn [cnt] (if (> cnt 10) cnt (recur (+ cnt 1)))) num)
... which, as you see, creates and calls an anonymous function.
You can even write loop
as a macro that makes this transformation:
(defmacro loop [bindings & body]
(let [[names values] (apply map vector (partition 2 bindings))]
`((fn ~names ~@body) ~@values)))
(loop [i 10, ans 0]
(case i
0 ans
(recur (dec i) (+ ans i))))
; 55
This may be slower than the proper clojure.core/loop
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With