(constantly x) 与 (fn [& _] x) 有何不同?

How does (constantly x) differ from (fn [& _] x)?

我正在使用多种方法来提供不同的功能,具体取决于 "mode" 我的项目 运行 在(它是一个 yada api 服务器,并且应该能够 运行 在 :dev:prod 模式等)。

我正在使用 mount/defstate 提供关键字:

(defstate mode :start :dev)

当我使用 (constantly mode) 发送时出现错误,但是当我使用 (fn [& _] mode) 发送时它似乎有效。

这两种形式不一样吗?或者它们的评估方式(或时间)是否存在细微差别?

mount 中,如果您尚未开始状态,则它们的值为 DerefableState 个对象。

通过调用 constantly,您首先计算 mode 的值,然后使用该值调用 constantly 函数。这意味着当您调用 constantly 的结果时,它总是 return constantly 的参数,尽管您已经更改了它。如果您在调用 constantly 之前尚未启动您的状态,那么它将存储 DerefableObject.

另一方面,使用 (fn [& _] mode) 时,每次调用函数时都会计算 mode var 的值。如果你还没有开始你的状态那么它也会 return 一个 DerefableState 但如果你已经开始那么结果将是预期的关键字。

一个简单的解决方案是将调度函数也置于状态中。

(defstate dispatch :start (constantly state))

我认为对于另一种解释,您可以使用副作用来突出差异。

比较:

(def const-f (constantly (println "Hello!")))
Hello!
=> #'user/const-f

(def fn-f (fn [] (println "World!")))
=> #'user/fn-f

只执行第一个 def 会导致打印 Hello!,因为立即评估 constantly 的主体。然而,第二个 def 不打印任何内容,因为 fn 的主体未被评估。

尽管打电话给他们时:

(const-f)
=> nil ; Prints nothing. Just evaluates to what println returned

(fn-f)
World! ; Prints now,
=> nil ;  then returns what println evaluates to

constantly 不是宏,因此必须首先评估它的参数。 fn 但是 一个宏,因此它在评估其参数之前运行。