在clojure中让vs def
Posted
技术标签:
【中文标题】在clojure中让vs def【英文标题】:let vs def in clojure 【发布时间】:2010-10-11 23:43:31 【问题描述】:我想在 clojure 程序中创建 Java Scanner
类的本地实例。为什么这不起作用:
; gives me: count not supported on this type: Symbol
(let s (new Scanner "a b c"))
但它会让我创建一个像这样的全局实例:
(def s (new Scanner "a b c"))
我的印象是唯一的区别是范围,但显然不是。 let
和def
有什么区别?
【问题讨论】:
【参考方案1】:问题是你对let
的使用是错误的。
let
是这样工作的:
(let [identifier (expr)])
所以你的例子应该是这样的:
(let [s (Scanner. "a b c")]
(exprs))
您只能在 let 的范围内使用由 let 进行的词法绑定(左括号和右括号)。让我们创建一组词法绑定。我使用 def 来进行全局绑定,而让让我只在 let 范围内绑定我想要的东西,因为它可以保持干净。它们都有各自的用途。
注意:(Class.) 与 (new Class) 相同,只是语法糖。
【讨论】:
【参考方案2】:LET 不是“在当前范围内进行词法绑定”,而是“使用以下绑定创建新的词法范围”。
(让 [s (foo 随便)] ;; s 绑定在这里 ) ;;但不是在这里 (def s (foo 随便)) ;; s 绑定在这里【讨论】:
我明白了,有点像 C# 的 using 或 Python 的 with 但没有任何破坏(无论如何,这将是一种愚蠢的不可变状态)。【参考方案3】:简化:def 用于全局常量,let 用于局部变量。
【讨论】:
不,这过于简单化了,而这恰恰导致了原始提问者的困惑。 LET 创建一个带有词法绑定的 new_block,而 DEF 只创建一个新的“全局”绑定。 对我来说听起来不对。 Def 总是绑定到 Var,因此不是常量。命名空间绑定也可以更改,因此它们甚至不是一个常量。 Let 是一个常数,它根本无法更改或重新绑定。所以至少我会说:“def 用于全局变量,let 用于局部常量。【参考方案4】:正确的语法:
(let [s (Scanner. "a b c")] ...)
【讨论】:
【参考方案5】:它们的语法是不同的,即使含义是相关的。
let 接受一个绑定列表(名称值对),后跟表达式以在这些绑定的上下文中求值。
def 只接受一个绑定,而不是一个列表,并将其添加到全局上下文中。
【讨论】:
【参考方案6】:您可以将let
视为使用fn
创建新词法范围然后立即应用它的语法糖:
(let [a 3 b 7] (* a b)) ; 21
; vs.
((fn [a b] (* a b)) 3 7) ; 21
所以你可以用一个简单的宏和fn
来实现let
:
(defmacro fnlet [bindings & body]
((fn [pairs]
`((fn [~@(map first pairs)] ~@body) ~@(map last pairs)))
(partition 2 bindings)))
(fnlet [a 3 b 7] (* a b)) ; 21
【讨论】:
以上是关于在clojure中让vs def的主要内容,如果未能解决你的问题,请参考以下文章
Clojure: cons (seq) vs. conj (list)