Binding 使用Clojure在运行时进行动态函数绑定

Binding 使用Clojure在运行时进行动态函数绑定,binding,coding-style,clojure,Binding,Coding Style,Clojure,我今天开始玩Clojure,无意中发现了一个说法,即可以在运行时动态更改函数。 这听起来很酷,所以我用这个特性写了一段代码 (defn ^:dynamic state [x] (odd x)) (defn even [x] (if (= x 0) (println "even") (binding [state odd] (parity x)))) (defn odd [x] (if (= x 0) (println "odd") (bindin

我今天开始玩Clojure,无意中发现了一个说法,即可以在运行时动态更改函数。 这听起来很酷,所以我用这个特性写了一段代码

(defn ^:dynamic state [x]
   (odd x))

(defn even [x]
  (if (= x 0)
    (println "even")
    (binding [state odd] (parity x))))

(defn odd [x]
  (if (= x 0)
    (println "odd")
    (binding [state even](parity x))))

(defn parity [x]
    (state (dec x)))
这很好,但由于我对Clojure完全陌生,我不知道这是否是
a) 干净的功能代码(因为奇数和偶数似乎有副作用?
b) 在运行时更改函数的方式应该是这样的

如果您能给我任何建议,我将不胜感激!:)
-Zakum

动态绑定的使用主要是一个品味问题,但有一些注意事项:

动态绑定几乎是在调用堆栈上显式传递值的快捷方式。只有少数情况下,这样做是完全明显的胜利;主要是通过不支持“全局”配置设置/参数的API传递这些设置/参数

依赖于动态绑定的API很难包装成更显式的内容,而另一种方式则容易得多(通常可以半自动完成)

动态绑定不能很好地处理惰性序列或在当前调用堆栈之外进行计算的任何其他内容(与其他线程一样)


总之,我认为“更干净”的函数解决方案是将
状态
作为参数传递给
奇偶校验
,但参数可以采用任何一种方式。

虽然能够将符号动态绑定到不同的函数,但我猜您真正想要的是重新定义函数

可以这样想:代码创建一个符号和两个函数,并将符号动态绑定到不同的函数:

                                   +---> func1
                                  /
symbol ---- [dynamic binding] ---<
                                  \
                                   +---> func2
这样的更改将永久影响所有使用
func1
的代码。在开发clojure时,这是一项正常的任务:您很可能在运行的应用程序上打开了一个REPL,并且多次重复使用相同的符号,动态地重新定义应用程序的所有移动部分


如果您使用的是Emacs和SLIME/Swank,那么每当您在修改后的Clojure源文件上点击
C-C-k
,您就有可能重新定义名称空间中的所有函数,而无需重新启动应用程序。

我真的不认为这是我要做的(虽然我不确定^^)。你告诉我的是我可以写一个函数,使用它,重新定义它,再次使用它,等等,对吗?对我来说,这是静态的,因为更改是由程序员手动完成的。我对编写在运行时更改其他函数的函数感兴趣。一个更实际的例子是向现有函数添加日志记录。一个自身发生变化的函数将是一个更特殊的例子。Clojure中的AFAIK动态变量在变量绑定上操作,而不是在符号上操作。感谢您的见解,Joost!那么我对你的理解是对的,我所做的不是亵渎?我知道,人们可以用不同的方式编写此功能。但我至少在Clojure中捕捉到了动态绑定的概念了吗?就我个人而言,我会在使用动态绑定之前尝试使用显式传递值,这主要是因为我提到的绑定的缺点,但它可以使代码更清晰、更容易。
(defn func1 [...])

(var func1) ; ---> func1

(defn func1 [...])

(var func1) ; ---> func1*