假设我要在局部范围内定义两个相互递归的函数。我可以用letfn做到这一点:
(letfn
[(f [x] (if (= x 0) (g x) true))
(g [x] (if (= x 1) (f x) false))]
(f 0))
但是与letfn
相比,let
受到了很大的限制,因为它仅接受“函数规范”,而不接受任意表达式。我的问题是:如果我想将元数据(使用with-meta
附加到f
和g
上,以便在f
内可以读取g
,该怎么办?的元数据,并且可以在g
内读取f
的元数据?在Clojure中有可能吗?
(对于上下文,我试图实现一个类似fn
的宏,该宏将某些元数据自动附加到正在创建的函数中。我希望这些自动注释的fn
可以在任何地方实例化普通的Clojure函数是包含在letfn
中的函数,但是我看不到如何定义一个像元letfn
那样的宏来附加元数据,因为它最终必须对{{1 }},无法附加元数据。)
答案 0 :(得分:3)
我找到了以下解决方案,其中使用letfn
来定义对实际函数f
和g
求值的重排:
(letfn [(f-thunk []
(with-meta (fn f [] (let [g (g-thunk)] (meta g))) {:f 3}))
(g-thunk []
(with-meta (fn g [] (let [f (f-thunk)] (meta f))) {:g 2}))]
(let [f (f-thunk) g (g-thunk)]
[(f) (g)]))
答案 1 :(得分:3)
不要忘记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})
有结果:
(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}
您还可以使用var-get
和var-set
来访问/更改本地变量的值。