即使我使用过Clojure,我还没有详细查看范围规则.当我阅读文档时,我变得更加困惑.我做了一个小测试来尝试确定范围,并对复杂性感到沮丧.有人可以解释Clojure使用的意图和各种规则吗?
(def x 1)
(defn dummy-fn2[]
(+ x 1))
(defn dummy-fn[]
(println "entering function: " x)
(let [x 100]
(println "after let: " x)
(let [x (dummy-fn2)]
(println "after let and dummy2: " x)
(binding [x 100]
(println "after binding: " x)
(let [x (dummy-fn2)]
(println "after binding and dummy2: " x))))))
1:2 foo=> (dummy-fn)
entering function: 1
after let: 100
after let and dummy2: 2
after binding: 2
after binding and dummy2: 101
nil
Run Code Online (Sandbox Code Playgroud)
Bri*_*per 24
letx使用本地阴影调制toplevel Var x. let不会创建Var或影响toplevel Var; 它绑定一些符号,以便对该符号的本地引用将替换为let-bound值. let具有词法范围,因此其绑定仅在let表单本身内可见(而不是在其中调用的函数中let).
binding临时(线程本地)更改顶级Var的值x,这就是它所做的全部.如果let绑定到位,binding在决定要更改哪个值时不会看到它(并且let绑定不是变量并且不可更改,因此'好事或者它会给您一个错误).并且binding不会掩盖let. binding具有动态范围,因此它对于顶层Vars的影响在binding表单和从binding表单内调用的任何函数中都是可见的.
访问plain old的值x将为您提供绑定堆栈顶部的任何内容,或者是最嵌套的绑定let值x(或调用的函数参数x,或者x如果您使用自己的宏,则替换某些值,或其他可能性.),并且x如果没有其他绑定,则默认情况下仅使用顶层Var的当前值.
即使顶层瓦尔x由掩盖let结合的x,你可以随时访问通过顶层无功@#'x.尝试这个版本,也许它会更有意义:
(def x 1)
(defn dummy-fn2[]
(println "x from dummy-fn2:" x)
(+ x 1))
(defn dummy-fn[]
(println "entering function:" x)
(println "var x:" @#'x)
(dummy-fn2)
(println "---")
(let [x 100]
(println "after let:" x)
(println "var x:" @#'x)
(dummy-fn2)
(println "---")
(let [x (dummy-fn2)]
(println "after let and dummy-fn2:" x)
(println "var x:" @#'x)
(dummy-fn2)
(println "---")
(binding [x 888]
(println "after binding:" x)
(println "var x:" @#'x)
(dummy-fn2)
(println "---")
(let [x (dummy-fn2)]
(println "after binding and dummy2:" x)
(println "var x:" @#'x)
(dummy-fn2)
(println "---"))))))
Run Code Online (Sandbox Code Playgroud)
得到:
entering function: 1
var x: 1
x from dummy-fn2: 1
---
after let: 100
var x: 1
x from dummy-fn2: 1
---
x from dummy-fn2: 1
after let and dummy-fn2: 2
var x: 1
x from dummy-fn2: 1
---
after binding: 2
var x: 888
x from dummy-fn2: 888
---
x from dummy-fn2: 888
after binding and dummy2: 889
var x: 888
x from dummy-fn2: 888
---
Run Code Online (Sandbox Code Playgroud)
Art*_*ldt 14
Clojure使用符号的词法范围 let和vars的动态范围 binding检查clojure的vars文档.
| 归档时间: |
|
| 查看次数: |
3981 次 |
| 最近记录: |