在Clojure中使用元数据创建相互递归的局部函数

时间:2019-02-08 06:57:54

标签: clojure

假设我要在局部范围内定义两个相互递归的函数。我可以用letfn做到这一点:

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

但是与letfn相比,let受到了很大的限制,因为它仅接受“函数规范”,而不接受任意表达式。我的问题是:如果我想将元数据(使用with-meta附加到fg上,以便在f内可以读取g,该怎么办?的元数据,并且可以在g内读取f的元数据?在Clojure中有可能吗?

(对于上下文,我试图实现一个类似fn的宏,该宏将某些元数据自动附加到正在创建的函数中。我希望这些自动注释的fn可以在任何地方实例化普通的Clojure函数是包含在letfn中的函数,但是我看不到如何定义一个像元letfn那样的宏来附加元数据,因为它最终必须对{{1 }},无法附加元数据。)

2 个答案:

答案 0 :(得分:3)

我找到了以下解决方案,其中使用letfn来定义对实际函数fg求值的重排:

(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-getvar-set来访问/更改本地变量的值。

相关问题