clojuredesign-podcast

Discussions around the Functional Design in Clojure podcast - https://clojuredesign.club/
jrwdunham 2020-10-21T16:39:06.035100Z

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!

nate 2020-10-21T17:15:19.035200Z

oh, that's cool!

nate 2020-10-21T17:15:26.035400Z

thanks for pointing that out.

1
nate 2020-10-21T17:16:58.035600Z

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.

nate 2020-10-21T17:17:00.035800Z

very cool

lodin 2020-10-21T20:18:07.036100Z

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

lodin 2020-10-21T20:20:07.036500Z

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

lodin 2020-10-21T20:22:42.036700Z

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

nate 2020-10-21T21:40:37.037Z

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

nate 2020-10-21T21:40:55.037200Z

interesting point about mutual recursion

nate 2020-10-21T21:41:16.037400Z

I haven't needed to do that much so far, but I'll try to remember it next time I do

nate 2020-10-21T21:41:26.037600Z

reminds me of the trampoline function