clojure - 重新定义 Clojure 中的函数

标签 clojure

我想根据这些函数的一些元数据在启动时重新定义程序中的一些函数。

我是 clojure 新手,所以我想知道完成此操作的惯用方法是什么。

我想做的是使用缓存(如memcache)来缓存某些函数的结果(数据库结果)。以类似于 memoize 或 contrib core.cache 的方式,但我想根据定义缓存策略的元数据,对程序的其余部分透明地重新定义原始函数。

Java 库通常使用注释和代码生成来完成此任务。但我想知道 clojure 完成此任务的惯用方法是什么?

我在互联网上探索了一些选项,但它们似乎不太令人满意。 绑定(bind)不是我想要的,因为它只适用于当前线程。 其他选项似乎正在使用一些我想避免的内部 java 函数,或者 使用 eval 绑定(bind)ns并重新优化函数。

我知道我可以使用 (keys (ns-publics 'foo)) 列出一个命名空间中的潜在函数,但尚未探索如何列出非公共(public)函数以及如何列出可用命名空间(当前已加载?) -也许有我可以使用的命名空间加载钩子(Hook)?

编辑: 这是我的想法的一个小例子。 Wrap 是一个根据 origs 元数据执行缓存的函数。示例中缺少缓存和元数据,并且wrapp 和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))

评估最后两种形式后,应重新定义 orig 和 orig2 以使用包装版本。 不幸的是,我在 REPL 中收到以下错误:

java.lang.IllegalStateException:无法更改/建立根绑定(bind):orig with set (NO_SOURCE_FILE:0)

最佳答案

您可以再次使用def/defn,它将更改函数的定义(从技术上讲,它将编写一个使用相同名称的新定义)。

所以你可以这样做:

(def orig (wrap orig))
(def orig2 (wrap orig2))

此外,如果我理解您的意图:wrap 应该返回一个函数,而不是结果。

(defn wrap [f]
  (fn [& args]
    (let [res (apply f args)]
      (println "wrap" f args "=" res)
      res)))

如果您查看 memoize 标准函数,它正是以这种方式工作的。

关于clojure - 重新定义 Clojure 中的函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8734233/

相关文章:

sql - 使用 Korma 插入数据库行

python - csv 数据可以变得懒惰吗?

Clojure,使用循环函数进行映射

emacs - 什么时候通过 nREPL 重新加载命名空间还不够,需要重新启动整个服务器进程(甚至 REPL)?

clojure - 如何找出两个数据集的差异?

binding - 为什么我不能在clojure中绑定(bind)+?

clojure - Clojure 中的一个引用还是多个引用?

clojure - Clojure 特殊形式 `def` 是否总是创建一个新的 Var?

multithreading - Clojure 实现多线程的最佳方式?

java - 是 :gen-class is the only way to extend Java class in Clojure?