【问题标题】:How does (constantly x) differ from (fn [& _] x)?(constantly x) 与 (fn [& _] x) 有何不同?
【发布时间】:2018-07-21 04:59:53
【问题描述】:

我正在使用多方法提供不同的功能,具体取决于我的项目运行的“模式”(它是yada api 服务器,应该能够在:dev:prod 模式等下运行) .

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

(defstate mode :start :dev)

当我使用 (constantly mode) 发送时,我会收到错误,但当我使用 (fn [& _] mode) 发送时,它似乎可以工作。

这两种形式不一样吗?还是在评估方式(或评估时间)方面存在细微差别?

【问题讨论】:

  • 请添加错误

标签: clojure expression-evaluation


【解决方案1】:

mount 中,如果您还没有开始您的状态,那么它们的值就是DerefableState 对象。

通过调用constantly,您首先评估mode 的值,然后使用该值调用constantly 函数。这意味着当您调用 constantly 的结果时,它总是会不断返回参数 of,尽管您已经更改了它。如果您在调用constantly 之前尚未开始您的状态,那么它将存储DerefableObject

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

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

(defstate dispatch :start (constantly state))

【讨论】:

  • 谢谢你,很好的解释。说constantly 表单关闭mode 是否正确,因为它存在于编译时,而fn 表单在运行时评估mode
  • constantly 关闭 mode 不是在编译时而是在运行时调用它。
  • 我尝试按照您的建议将调度放入defstate,但我从(defmulti fn-name dispatch) 行获得mount.core.DerefableState cannot be cast to clojure.lang.IFn。我想我明白为什么会这样。我误解了你的建议吗?
  • hmm,这取决于您如何使用dispatch,但可能与上面相同:您在 Mount 启动之前使用它的值。尝试使用#'dispatch 而不是dispatch 可能吗?
【解决方案2】:

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

比较:

(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 然而一个宏,所以它在其参数被评估之前运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-01
    • 2022-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多