我想根据这些函数的一些元数据在启动时重新定义我的程序中的一些函数.
我是clojure的新手,所以我想要实现这一目标的惯用方法是什么.
我想要做的是使用缓存(如memcache)来缓存某些函数的结果(数据库结果).以类似于memoize或contrib core.cache的方式,但我想根据定义缓存策略的元数据,将原始函数透明地重新定义到程序的其余部分.
Java库通常使用注释和代码生成来实现此目的.但我正在徘徊什么是惯用的方法来完成这个?
我已经在互联网上探讨了一些选项,但它们似乎并不太令人满意.绑定不是我想要的,因为它只适用于当前线程.其他选项似乎是使用一些内部java函数,我想避免,或绑定ns和使用eval重新引用函数.
我知道我可以用(keys-ns-publics'foo))列出一个命名空间中的潜在函数,但还没有探讨如何列出非公共函数以及如何列出可用的命名空间(当前已加载?) - 也许有命名空间加载钩我可以使用?
编辑:这是我想到的一个小例子.Wrap是一个根据origs元数据执行缓存的函数.示例中不存在缓存和元数据,wrap和orig都在同一名称空间中.
(defn orig []
"OK")
(defn orig2 []
"RES 2")
(defn wrap [f & args]
(let [res (apply f args)]
println "wrap" f args "=" res
res))
(set! orig (wrap orig))
(set! orig2 (wrap orig2))
Run Code Online (Sandbox Code Playgroud)
在评估了最后两个表单后,orig和orig2应该重新定义为使用包装版本.不幸的是我在REPL中收到以下错误:
java.lang.IllegalStateException:无法更改/建立root的绑定:orig with set(NO_SOURCE_FILE:0)
您可以def/defn再次使用它将更改函数的定义(从技术上讲,它将编写一个使用相同名称的新定义).
所以你可以这样做:
(def orig (wrap orig))
(def orig2 (wrap orig2))
Run Code Online (Sandbox Code Playgroud)
另外,如果我理解你的意图:wrap应该返回一个函数,而不是结果.
(defn wrap [f]
(fn [& args]
(let [res (apply f args)]
(println "wrap" f args "=" res)
res)))
Run Code Online (Sandbox Code Playgroud)
如果你看一下memoize标准功能,它就会以这种方式工作.