gpt4 book ai didi

clojure - Clojure 可以完全动态化吗?

转载 作者:行者123 更新时间:2023-12-02 06:31:29 26 4
gpt4 key购买 nike

在 clojure 1.1 中,所有调用都是动态的,这意味着您可以在 REPL 中重新定义函数,并且它将自动包含在正在运行的程序中。这对于 dotrace 之类的东西也很好。

在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 在下面指出,这里实际发生的是阶乘中的 self 调用正在被优化掉。我不明白为什么要这样做,因为你不能在不破坏堆栈的情况下进行那么多递归 self 调用,但它解释了观察到的行为。也许这与匿名 self 调用有关。

我问题的最初原因是我试图写 http://www.learningclojure.com/2011/03/hello-web-dynamic-compojure-web.html ,并且我对必须输入 #' 才能获得我期望的行为的地方数量感到恼火。那和 dotrace 让我认为一般的动态行为已经消失,并且在某些地方有效的动态重新定义必须通过一些聪明的技巧来完成。

回想起来,这似乎是一个奇怪的结论,但现在我只是感到困惑(这更好!)。这一切有什么引用资料吗?我很想有一个关于什么时候有效、什么时候无效的一般理论。

最佳答案

Clojure 中的所有内容都是完全动态的,但是您必须注意何时使用 Var 以及何时使用 Function该 Var 的当前

在第一个示例中:

(defn factorial [n] (if (< n 2) n (* n (factorial (dec n)))))

factorial 符号被解析为 Var #'user/factorial,然后由编译器求值以获得其当前值,即一个已编译函数。此评估仅在编译函数时发生一次。第一个示例中的 factorial 是定义函数时 Var #'user/factorial

在第二个示例中:

(defn factorial [n] (if (< n 2) n (* n (#'factorial (dec n)))))

您已明确要求提供 Var #'user/factorial。调用 Var 与取消引用 Var 并调用其(函数)值具有相同的效果。这个例子可以更明确地写成:

(defn factorial [n] (if (< n 2) n (* n ((deref (var factorial)) (dec n)))))

clojure.contrib.trace/dotrace 宏(我多年前编写的)使用 binding 暂时将 Var 重新绑定(bind)到不同的值。它不会改变任何函数的定义。相反,它创建一个新函数,该函数调用原始函数并打印跟踪行,然后将该函数绑定(bind)到 Var。

在第一个示例中,由于原始函数是使用 factorial 函数的进行编译的,因此 dotrace 没有任何效果。在第二个示例中,每次调用 factorial 函数都会查找 #'user/factorial Var 的当前值,因此每次调用都会看到由 创建的备用绑定(bind)>dotrace

关于clojure - Clojure 可以完全动态化吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5398569/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com