Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating mutually recursive local functions with metadata in Clojure

Tags:

clojure

Suppose I want to define two mutually recursive functions within a local scope. I can do this with letfn:

(letfn 
  [(f [x] (if (= x 0) (g x) true))
   (g [x] (if (= x 1) (f x) false))]
 (f 0))

But letfn is quite restricted, compared to let, as it accepts only "function specs," not arbitrary expressions. My question is: what if I want to attach metadata (using with-meta) to both f and g, so that within f, I can read g's metadata, and within g, I can read f's metadata? Is this possible in Clojure?

(For context, I am trying to implement a fn-like macro that automatically attaches certain metadata to the function being created. I'd like these auto-annotated fns to be instantiable wherever a normal Clojure function is, including inside a letfn. But I don't see how I can define a letfn-like macro that attaches the metadata, because it would ultimately have to desugar to letfn, which cannot attach metadata.)

like image 940
Alex Lew Avatar asked May 13 '26 15:05

Alex Lew


1 Answers

Don't forget about with-local-vars:

  (with-local-vars [f (fn [x] (if (= x 0) (g x) true))
                    g (fn [x] (if (= x 1) (f x) false))]
    (reset-meta! f {:f 3})
    (reset-meta! g {:g 2})

with results:

(f 0) => false
(f 1) => true

f           => #<Var: --unnamed-->
(var-get f) => #object[tst.demo.core$fn__20698$fn__20699 0x1eb2d718 "tst.demo.core$fn__20698$fn__20699@1eb2d718"]
(meta f)    => {:f 3}
(meta g)    => {:g 2}

You can also use var-get and var-set to access/change the value of the local vars.

like image 137
Alan Thompson Avatar answered May 16 '26 08:05

Alan Thompson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!