letfn
lets you define recursive functions while (let [my-fn (fn ...)])
does not — one of the benefits of letfn
that occurred to me while listening to your let
cast. Enjoyed it. Thanks guys!
oh, that's cool!
thanks for pointing that out.
from <https://clojuredocs.org/clojure.core/letfn>
:
> All of the names are available in all of the definitions of the functions, as well as the body.
very cool
Anonymous functions can be recursive. Most of the time you can use recur
. If you have multiple arities you can name the anonymous (!) function, e.g. (fn my-func ([x] (my-func x nil)) ([x y] ...))
. You only need let-fn
when you want local mutually recursive functions. And even then you could hack around it using atoms (which is essentially what Clojure does at the top level, when you use declare
). Example:
(let [odd? (atom nil)
even? (fn even? [n]
{:pre [(integer? n)]}
(cond
(pos? n) (@odd? (dec n))
(zero? n) true
:else (even? (- n))))
_ (reset! odd? (fn [n]
(cond
(zero? n) false
:else (even? (dec n)))))
odd? @odd?]
[(map (complement odd?) (range -3 (inc 3)))
(map even? (range -3 (inc 3)))])
And if you want to go crazy, you can use the Y combinator for mutually recursive functions, like so:
(let [[even? odd?] (Y* (fn [even? odd?]
(fn [n]
{:pre [(integer? n)]}
(cond
(pos? n) (odd? (dec n))
(zero? n) true
:else (even? (- n)))))
(fn [even? odd?]
(fn [n]
(cond
(zero? n) false
:else (even? (dec n))))))]
[(map (complement odd?) (range -3 (inc 3)))
(map even? (range -3 (inc 3)))])
And the Y* function uses no magic or atoms, even though it is incomprehensible. 🙂 (You can just google "y combinator mutual recursion" to find a version of it.)
Woah, @lodin.johan that's some intense code. thanks for posting it
interesting point about mutual recursion
I haven't needed to do that much so far, but I'll try to remember it next time I do
reminds me of the trampoline function