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