clojureのlet vs def
質問
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
の違いは何ですか?
解決
問題は、 let
の使用が間違っていることです。
次のように動作します:
(let [identifier (expr)])
したがって、例は次のようになります。
(let [s (Scanner. "a b c")]
(exprs))
letのスコープ内では、letで作成された字句バインディングのみを使用できます(開き括弧と閉じ括弧)。字句バインディングのセットを作成してみましょう。グローバルバインディングを作成するためにdefを使用し、letのスコープ内でのみ必要なものをバインドできるようにします。両方とも用途があります。
注:(クラス)は(新しいクラス)と同じで、単なる構文上の砂糖です。
他のヒント
LETは「現在のスコープでレキシカルバインディングを作成する」ではなく、「次のバインディングで新しいレキシカルスコープを作成する」です。
(let [s (foo whatever)] ;; s is bound here ) ;; but not here
(def s (foo whatever)) ;; s is bound here
正しい構文:
(let [s (Scanner. "a b c")] ...)
簡易: def はグローバル定数用、 let はローカル変数用です。
意味が関連していても、それらの構文は異なります。
letは、バインディングのリスト(名前と値のペア)の後に式が続き、それらのバインディングのコンテキストで評価します。
defはリストではなく1つのバインディングを取得し、グローバルコンテキストに追加します。
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
所属していません StackOverflow