문제

I never really thought about this until I was explaining some clojure code to a coworker who wasn't familiar with clojure. I was explaining let to him when he asked why you use a vector to declare the bindings rather than a list. I didn't really have an answer for him. But the language does restrict you from using lists:

=> (let (x 1) x)
java.lang.IllegalArgumentException: let requires a vector for its binding (NO_SOURCE_FILE:0)

Why exactly is this?

도움이 되었습니까?

해결책

Mostly readability, I imagine. Whenever bindings are needed in Clojure, a vector is pretty consistently used. A lot of people agree that vectors for bindings make things flow better, and make it easier to discern what the bindings are and what the running code is.

Just for fun:

user=> (defmacro list-let [bindings & body] `(let ~(vec bindings) ~@body))
#'user/list-let
user=> (macroexpand-1 '(list-let (x 0) (println x)))
(clojure.core/let [x 0] (println x))
user=> (list-let (x 0 y 1) (println x y))
0 1
nil

다른 팁

This is an idiom from Scheme. In many Scheme implementations, square brackets can be used interchangeably with round parentheses in list literals. In those Scheme implementations, square brackets are often used to distinguish parameter lists, argument lists and bindings from S-expressions or data lists.

In Clojure, parentheses and brackets mean different things, but they are used the same way in binding declarations.

Clojure tries very hard to be consistent. There is no technical reason with a list form could not have been used in let, fn, with-open, etc... In fact, you can create your own my-let easily enough that uses one instead. However, aside from standing out visibly, the vector is used consistently across forms to mean "here are some bindings". You should strive to uphold that ideal in your own code.

my guess is that it's a convention

fn used it, defn used it, loop uses.

it seems that it's for everything that resembles a block of code that has some parameters; more specific, the square brackets are for marking those parameters

other forms for blocks of code don't use it, like if or do. they don't have any parameters

Another way to think about this is that let is simply derived from lambda. These two expressions are equivalent:

((fn [y] (+ y 42)) 10)
(let [y 10] (+ 42 y))

So as an academic or instructional point, you could even write your own very rudimentary version of let that took a list as well as a vector:

(defmacro my-let [x body]
  (list (list `fn[(first x)]
              `~body)
        (last x)))

(my-let (z 42) (* z z))

although there would be no practical reason to do this.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top