【问题标题】:clojure and ^:dynamicclojure 和 ^:dynamic
【发布时间】:2012-07-28 16:07:11
【问题描述】:

我试图理解动态变量和绑定函数,所以我尝试了这个(clojure 1.3):

user=> (defn f [] 
           (def ^:dynamic x 5) 
           (defn g [] (println x)) 
           (defn h [] (binding [x 3] (g))) 
           (h))
#'user/f
user=> (f)     
5
nil

困惑,我尝试了这个更简单的代码:

user=> (def ^:dynamic y 5)
#'user/y
user=> (defn g [] (println y))
#'user/g
user=> (defn h [] (binding [y 3] (g)))
#'user/h
user=> (h)
3
nil

这两段代码有什么区别?为什么第二个例子有效,而第一个无效?

提示:我刚刚意识到以下工作(仍然不完全理解为什么):

user=> (def ^:dynamic y 5)
#'user/y
user=> (defn f [] (defn g [] (println y)) (defn h [] (binding [y 3] (g))) (h))
#'user/f
user=> (f)
3
nil
user=> 

【问题讨论】:

    标签: clojure dynamic-scope


    【解决方案1】:

    当我在 Clojure 1.4 中运行您的第一个示例时,结果是 3(如您所料)......您是否尝试过使用新的 REPL?

    ^:dynamic 是向 Clojure 编译器发出的一条指令,指示符号(使用 def 定义)旨在动态反弹(使用 binding)。

    例子:

    (def foo 1)
    (binding [foo 2] foo)
    => IllegalStateException Can't dynamically bind non-dynamic var: ...
    
    (def ^:dynamic bar 10)
    (binding [bar 20] bar)    ;; dynamically bind bar within the scope of the binding
    => 20
    bar                       ;; check underlying value of bar (outside the binding)
    => 10
    

    请注意,binding 在调用线程内具有动态范围 - 在绑定内调用的任何函数都将看到 bar (20) 的修改值,但任何其他线程仍将看到未更改的根值 10。

    最后是一些对你有帮助的风格要点:

    • 通常认为将defdefn 放在函数中是个坏主意,因为它们会影响封闭的命名空间。在函数中,您应该改用 (let [foo bar] ...)
    • 当您发现自己想要使用binding 时,您通常应该考虑是否可以使用高阶函数来实现相同的结果。 binding 在某些情况下很有用,但通常不是传递参数的好方法 - 从长远来看,函数组合通常更好。原因是 binding 创建了一个隐式上下文,这是执行函数所需的,这可能难以测试/调试。

    【讨论】:

    • 我了解绑定的优缺点。我也意识到第一个代码示例是不寻常的 clojure 代码。我不明白为什么它不起作用(1.3,新鲜的repl)。
    • 我不知道你什么时候想要装订!它看起来很讨厌功能性的方式。我错过了什么?
    • @Hendekagon - 本身可能值得一个 SO 问题。但是我发现它作为在 REPL 调试/工作时传递循环上下文的一种额外方式很有用 - 如果你以纯粹的功能方式这样做,那么你需要通过一个(可能很长的)调用一直线程化新参数图表。
    • 我在 1.4 中尝试过,它可以正常工作(如预期的那样),并在 1.3 中重试,但失败了。我只能得出结论,1.3 中存在一些已修复的错误。
    • @Kevin ^:dynamic 在 1.3 中还不是语言的一部分——所以不,不是错误,只是还不存在;在那个时候,动态变量被命名为*barbells* 不仅仅是惯例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 1970-01-01
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    相关资源
    最近更新 更多