2010-10-04 1 views
14

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

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

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

+0

Я предполагаю, что это чисто для удобочитаемости, и, допустив применение вектора, просто обеспечивает сохранение идиомы. – MayDaniel

+0

(Литеральный вектор требуется для почти всех макросов «let» и «with-».) – MayDaniel

+1

Это вроде естественных законов. Вы можете рассуждать *, что это так, но не * почему *.Является ли настоящая причина этого решения читабельностью, некоторые реализации Схемы, конвенция или тип завтрака Богата в тот день остаются в темноте. Единственный, кто может ответить на этот вопрос, - это сам Рич. Для Clojure мы находимся в удачном положении, для вселенной .... – kotarak

ответ

25

В основном читаемость, я думаю. Всякий раз, когда привязки необходимы в 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 
+4

Я голосую за этот ответ, так как он избил мой на 2 минуты ** И ** имеет код! Хорошее шоу! – fogus

+3

Правда, Хикки упомянул о удобочитаемости в своем ... параллельном разговоре, я думаю, это так. –

+5

Использование символа буквально также дает понять, что это не вызов функции. list-let работает, но вы должны знать, что первый список не оценивается нормально. Если у вас есть буквенный векторный синтаксис, вы также можете воспользоваться им. –

11

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

13

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

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

+0

+1: это звучит как «почему» к соглашению. – progo

1

мое предположение, что это конвенция

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

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

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

1

Другой способ подумать об этом - 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)) 

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