Зачем нужен вектор?

Я никогда не думал об этом, пока не объяснил код clojure сотруднику, который не был знаком с clojure. Я объяснял ему let, когда он спросил, почему вы используете вектор для объявления привязок, а не списка. У меня на самом деле не было ответа на него. Но язык ограничивает использование списков:

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

Почему именно это?

Ответы

Ответ 1

В основном читаемость, я думаю. Всякий раз, когда привязки необходимы в Clojure, вектор довольно последовательно используется. Многие люди согласны с тем, что векторы для привязок делают вещи более эффективными и позволяют легче различать, что такое привязки и что работает.

Просто для удовольствия:

user=> (defmacro list-let [bindings & body] `(let ~(vec bindings) [email protected]))
#'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

Ответ 2

Это идиома из Схемы. Во многих реализациях Схемы квадратные скобки могут использоваться взаимозаменяемо с круглыми скобками в списковых литералах. В тех реализациях Схемы квадратные скобки часто используются для выделения списков параметров, списков аргументов и привязок из S-выражений или списков данных.

В Clojure круглые скобки и скобки означают разные вещи, но они используются одинаково в объявлениях привязки.

Ответ 3

Clojure очень сложно быть последовательным. Нет никаких технических причин, чтобы форма списка не могла использоваться в let, fn, with-open и т.д. На самом деле вы можете создать свой собственный my-let достаточно легко, чтобы использовать его вместо него. Однако, не выделяясь видимо, вектор последовательно используется в разных формах, чтобы обозначить "вот некоторые привязки". Вы должны стремиться поддерживать этот идеал в своем собственном коде.

Ответ 4

Я предполагаю, что это соглашение

fn использовал его, defn использовал его, loop использовал.

кажется, что он для всего, что напоминает блок кода, который имеет некоторые параметры; более конкретно, квадратные скобки предназначены для маркировки этих параметров

другие формы для блоков кода не используют его, например if или do. у них нет параметров

Ответ 5

Еще один способ подумать о том, что let просто выведен из лямбда. Эти два выражения эквивалентны:

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

Итак, как академический или учебный пункт, вы могли бы даже написать свою собственную очень рудиментарную версию let, которая взяла бы список, а также вектор:

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

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

хотя практических оснований для этого не было.