在Clojure 1.2中,许多调用似乎是静态链接的,如果我想替换一个函数,有时候我必须找到所有调用它的地方并在它们前面放置#'。
更糟糕的是,我无法预测何时需要这样做。
是否可以回到旧的默认动态链接方式?也许如果你需要额外的速度优势,你可以为生产应用程序切换回来,但是在开发过程中,我更喜欢1.1的行为。
我希望有一种编译器选项,类似于*warn-on-reflection*。
编辑:
我对正在发生的事情感到困惑。更具体地说,这里有两个函数。我喜欢第二个的行为。如何使第一个函数的行为像第二个函数,因为我认为它在1.1中就是这样做的?
user> (clojure-version)
"1.2.0"
user> (defn factorial[n] (if (< n 2) n (* n (factorial (dec n)))))
#'user/factorial
user> (require 'clojure.contrib.trace)
user> (clojure.contrib.trace/dotrace (factorial) (factorial 10))
TRACE t1670: (factorial 10)
TRACE t1670: => 3628800
user> (defn factorial[n] (if (< n 2) n (* n (#'factorial (dec n)))))
#'user/factorial
user> (clojure.contrib.trace/dotrace (factorial) (factorial 10))
TRACE t1681: (factorial 10)
TRACE t1682: | (factorial 9)
TRACE t1683: | | (factorial 8)
TRACE t1684: | | | (factorial 7)
TRACE t1685: | | | | (factorial 6)
TRACE t1686: | | | | | (factorial 5)
TRACE t1687: | | | | | | (factorial 4)
TRACE t1688: | | | | | | | (factorial 3)
TRACE t1689: | | | | | | | | (factorial 2)
TRACE t1690: | | | | | | | | | (factorial 1)
TRACE t1690: | | | | | | | | | => 1
TRACE t1689: | | | | | | | | => 2
TRACE t1688: | | | | | | | => 6
TRACE t1687: | | | | | | => 24
TRACE t1686: | | | | | => 120
TRACE t1685: | | | | => 720
TRACE t1684: | | | => 5040
TRACE t1683: | | => 40320
TRACE t1682: | => 362880
TRACE t1681: => 3628800
3628800
编辑(整个问题和标题更改):
Joost在下面指出,实际上发生的是阶乘中的自我调用被优化掉了。我不明白为什么会这样做,因为你不能进行那么多递归的自我调用而不会导致堆栈溢出,但这可以解释观察到的行为。也许这与匿名自我调用有关。
我提出问题最初的原因是我试图编写http://www.learningclojure.com/2011/03/hello-web-dynamic-compojure-web.html,并且我对我必须输入#'的地方感到恼火,以获得我期望的行为。那个点追踪和其他一些东西使我想到了通用动态行为已经消失了,并且在一些地方工作的即时重新定义必须使用一些巧妙的技巧来完成。
回想起来,这似乎是一个奇怪的结论,但现在我只是困惑了(这还好!)。有没有关于所有这些的参考资料?我很想拥有一个通用的理论,了解何时会起作用,何时不会。