Fork me on GitHub
#clojuredesign-podcast
<
2020-10-21
>
jrwdunham16:10:06

`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!

nate17:10:19

oh, that's cool!

nate17:10:26

thanks for pointing that out. 3
nate17:10:58

from : > All of the names are available in all of the definitions of the functions, as well as the body.

nate17:10:00

very cool

lodin20:10:07

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)))])``````

lodin20:10:07

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)))])``````

lodin20:10:42

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.)

nate21:10:37

Woah, @U8J6W2SC8 that's some intense code. thanks for posting it

nate21:10:55

@U0510902N I don't even remember when I last needed that. And yeah, trampolining is probably a good idea for any recursion that doesn't use `recur` since there's no tail call optimization. It's been a long time since I needed trampoline as well. 🙂