【问题标题】:What does ^:dynamic do in Clojure?^:dynamic 在 Clojure 中做了什么?
【发布时间】:2013-04-01 02:40:30
【问题描述】:

我搜索了“clojure 动态”和“clojure 动态范围”并阅读了 10 多篇文章,但我仍然对 ^:dyanmic 的作用没有清晰的了解。 I think this article may be answering my question,但代码示例似乎“丢失”了,所以我什至不确定它是否指的是我感到困惑的同一件事。

我正在尝试解决clj-http 项目中的一个问题,但首先我必须了解代码。它的功能定义如下:

(defn ^:dynamic parse-html
  "Resolve and apply crouton's HTML parsing."
  [& args]
  {:pre [crouton-enabled?]}
  (apply (ns-resolve (symbol "crouton.html") (symbol "parse")) args))

但我不明白^:dynamic 的含义/作用。谁能用非常简单的方式向我解释一下?

【问题讨论】:

    标签: clojure


    【解决方案1】:

    它将函数定义为动态范围。

    换句话说,这允许某人在给定的函数调用中重新绑定parse-html,并使新绑定仅适用于从该特定调用调用的函数。

    如果parse-html 不是动态范围的,那么重新绑定将导致任何使用parse-html 的代码都可以看到新绑定,而不仅仅是由执行重新绑定的函数调用激活的代码。

    动态范围可用于替代全局范围的变量。一个函数可以说“让 current_numeric_base = 16;调用其他函数;”其他函数都将以十六进制打印。然后当它们返回时,基数设置函数返回,基数将返回到原来的状态。 http://c2.com/cgi/wiki?DynamicScoping


    正如在下面的 cmets 中所指出的,您实际上不能重新绑定在 Clojure 中没有动态作用域的变量。如果可以的话,更新一个词法范围的变量将影响所有执行的代码,即使它运行在与重新绑定发生位置不同的调用堆栈中。

    所以也许一些伪代码会让动态和词法范围之间的区别变得清晰。

    使用动态范围变量的示例:

    (def ^:dynamic a 0)
    
    (defn some-func [x] (+ x 1))
    
    ; re-binds a to 1 for everything in the callstack from the (binding)
    ; call and down
    (binding [a 1] 
       (print (some-func a)))
    
     ; a was only re-bound for anything that was called from
     ; within binding (above) so at this point a is bound to 0.
    (print (some-func a))
    

    将打印: 2 1

    词法范围变量示例:

    (def a 0)
    
    (defn some-func [x] (+ x 1))
    
    ; re-binds a to 1 for everyone, not just things that 
    ; are in the callstack created at this line
    (set-var [a 1]  ; set-var is a made up function that can re-bind lexically scoped variables
       (print (some-func a)))
    
    ; a was lexically scoped so changing it changed
    ; it globally and not just for the callstack that
    ; contained the set-var.
    (print (some-func a))
    

    将打印: 2 2

    【讨论】:

    • 酷,这是一个很好的答案,但如果您使用 ^:dynamic 向我展示一些示例代码并展示您解释的差异,我会觉得我会更好地理解它。你介意这样做吗?
    • 如果parse-html 没有动态作用域,那么重新绑定它就是非法的。
    猜你喜欢
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 2012-02-12
    • 2010-10-26
    • 2019-07-12
    • 2010-11-20
    相关资源
    最近更新 更多