在clojure中让vs
我想在clojure程序中创build一个Java Scanner类的本地实例。 为什么这不起作用:
;gives me: count not supported on this type: Symbol (let s (new Scanner "abc"))
但它会让我创build一个像这样的全局实例:
(def s (new Scanner "abc"))
我的印象是,唯一的区别是范围,但显然不是。 let和def有什么区别?
问题是你使用let
是错误的。
让这样的作品:
(let [identifier (expr)])
所以你的例子应该是这样的:
(let [s (Scanner. "abc")] (exprs))
你只能使用在let的范围内(let的开始和结束的parens)所做的词法绑定。 只需创build一组词汇绑定。 我使用def来进行全局绑定,并且只允许在let的范围内绑定我想要的东西,因为它使事情保持干净。 他们都有他们的用途。
注意:(类)与(新类)相同,只是语法上的糖。
LET不是“在当前范围内进行词汇绑定”,而是“以下面的绑定形成新的词汇范围”。
(让[s(foo无论)] ;; 这里是绑定的 ) ;; 但不在这里
(def s(foo whatever)) ;; 这里是绑定的
正确的语法:
(let [s (Scanner. "abc")] ...)
简化: def是全局常量, let是局部variables。
它们的语法是不同的,即使意义是相关的。
让我们获取绑定 (名称值对)后跟expression式来评估这些绑定的上下文。
def只需要一个绑定,而不是一个列表,并将其添加到全局上下文中。
你可以考虑let
语法糖当作fn
创build一个新的词法作用域,然后马上应用:
(let [a 3 b 7] (* ab)) ; 21 ; vs. ((fn [ab] (* ab)) 3 7) ; 21
所以你可以实现let
一个简单的macros和fn
:
(defmacro fnlet [bindings & body] ((fn [pairs] `((fn [~@(map first pairs)] ~@body) ~@(map last pairs))) (partition 2 bindings))) (fnlet [a 3 b 7] (* ab)) ; 21