在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"))

我的印象是唯一的区别是范围,但显然不是。 letdef有什么区别?

【问题讨论】:

【参考方案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的主要内容,如果未能解决你的问题,请参考以下文章

在VS中让多个源文件分开运行

Clojure vs Go - 泰坦之战!

Clojure: cons (seq) vs. conj (list)

在VS中让一个JS文件智能提示另一个JS文件中的成员2--具体引用

如何在Visual Studio中让应用程序访问数据库

webjure vs compojure?