Списки для S-выражений, Векторы для (буквальных) данных? - PullRequest
4 голосов
/ 12 декабря 2010

Я заметил свою привычку использовать векторы намного чаще, чем списки, когда мне нужен литерал для проверки функции, которая принимает последовательность.

Т.е.:

(map inc [1 2 3])

Но не:

(map inc (list 1 2 3))

Хотя оба они верны (и несколько дополнительных символов во втором можно решить с помощью кавычек).

Итак, я практически использую списки только для построения s-выражений, независимо от того, делаю ли я это вручную или в макросе.

Не принимая во внимание проблемы производительности, которые уже обсуждались здесь ,Какой стиль кодирования вы бы назвали лучшим?

Я знаю, что это немного субъективный вопрос, но мне пришло в голову, что, возможно, я переношу свое мышление "код и разделение данных" из своего опыта вязыки лисп.

Ответы [ 2 ]

4 голосов
/ 12 декабря 2010

Векторные литералы, когда производительность не имеет значения, обычно предпочтительнее списков;во-первых, их легче вводить и меньше символов, но (возможно) важнее: их легче читать.(проще отличить от вызовов функций и т.1005 * Исключение: let requires a vector for it's binding

(let [a 1] a) ;; => 1

3 голосов
/ 14 декабря 2010

Вектор в Clojure расплывчато означает «это данные».Группа привязок для let или fn - это просто данные.Это последовательность символов или последовательность пар символ-значение.

Список неопределенно означает «Это вызов функции или макроса».Когда вы видите список, вы будете в полной безопасности, если предположить, что первым в этом списке есть что-то вызываемое, а остальное в списке - аргументы к нему.

Существуют исключения.Вы увидите и (ns foo (:use (bar baz))) и (ns foo [:use [bar baz]]) в идиоматическом коде.Не уверен, почему кроме этого Clojure рос очень быстро и полуорганически в некоторых областях и все еще растет.Но это хорошее эмпирическое правило.

Векторы не нужно заключать в кавычки, что является хорошим способом избежать определенных ошибок, особенно если учесть, что многие вещи в Clojure могут вызываться как функции.(:foo :bar) не является списком из двух ключевых слов, но он будет скомпилирован, вызывая :foo в качестве поиска по ключевому слову для ключевого слова :bar, оцениваемого как nil.Там нет никакого способа испортить [:foo :bar].Это всегда вектор из двух ключевых слов.

Преимущество отсутствия необходимости заключать в кавычки элементы вектора не следует преуменьшать.Как бы вы хотели написать это списками?

(let [x 123 y 456] 
  [[:foo x] [:bar y]])

Один из способов настолько многословен, что ваши данные теряются в лесу list.Другой способ - это ненужный беспорядок в пунктуации.

(let [x 123 y 456] 
  (list (list :foo x) (list :bar y)))

(let [x 123 y 456] 
  `((:foo ~x) (:bar ~y)))

Clojure, возможно, меньше, чем суп из скобок, чем другие диалекты Lisp, благодаря [] и {}.Хотя некоторые люди не любят ))])}), которое имеет Clojure, я думаю, что лучше потерять себя в длинной строке )))))))).

«Код - это данные» не означает, что все ваши данныедолжен выглядеть как весь ваш код и наоборот.У вас есть доступ к коду как данным, когда он вам нужен, что редко, как правило, в макросах.Между тем, если ваши данные не являются кодом, почему они должны выглядеть как код?Последовательность телефонных номеров не является кодом.Нет причин, по которым он должен быть в списке.

И, как вы сказали, со списками есть проблемы с производительностью.

...