Почему Clojure idiom предпочитает возвращать нуль вместо пустого списка, такого как Scheme?
Из комментария к другому вопросу, кто-то говорит, что Clojure idiom предпочитает возвращать нуль, а не пустой список, как на Схеме. Почему это?
Как
(when (seq lat) ...)
вместо
(if (empty? lat)
'() ...)
Ответы
Ответ 1
Я могу думать о нескольких причинах:
-
Логическое различие. В Clojure nil означает ничего/отсутствие значения. Принимая во внимание, что "()" пустой список - это значение, это просто значение, которое является пустым списком. Это довольно часто концептуально и логически полезно для различения двух.
-
Fit with JVM - объектная модель JVM поддерживает нулевые ссылки. И довольно много API Java возвращают значение null, что означает "ничего" или "значение не найдено". Поэтому для обеспечения удобной совместимости с JVM имеет смысл использовать Clojure для использования nil аналогичным образом.
-
Лень - логика здесь довольно сложная, но я понимаю, что использование nil для "нет списка" лучше работает с Clojure ленивые последовательности. Поскольку Clojure является ленивым функциональным языком программирования по умолчанию, для этого использования имеет смысл быть стандартным. Подробнее см. http://clojure.org/lazy.
-
"Фальшивость" . Удобно использовать nil для обозначения "ничего", а также "false" при написании условного кода, который исследует коллекции, поэтому вы можете написать код типа (if (some-map :some-key) ....)
проверить, содержит ли хэш-карта значение для заданного ключа.
-
Производительность. Это более эффективно проверять на нуль, чем проверять список, чтобы увидеть, пуст ли он... поэтому принятие этой идиомы в качестве стандарта может привести к более высокому идиоматическому коду производительности
Обратите внимание, что в Clojure все еще есть некоторые функции, которые возвращают пустой список. Примером является отдых:
(rest [1])
=> ()
Этот вопрос о покойном и следующем объясняет, почему это.....
Ответ 2
Также обратите внимание, что объединение типов коллекций и nil образует моноид, с конкатенацией monoid plus и nil моноидным нулем. Таким образом, nil сохраняет пустую семантику списка под конкатенацией, а также представляет ложное или "отсутствующее" значение.
Python - это еще один язык, где общие моноидные идентификаторы представляют собой ложные значения: 0, пустой список, пустой кортеж.
Ответ 3
Из Радость Clojure
Поскольку пустые коллекции действуют как true
в булевых контекстах, вам нужна идиома для проверки того, есть ли что-нибудь в коллекции для обработки. К счастью, Clojure предоставляет такую технику:
(seq [1 2 3])
;=> (1 2 3)
(seq [])
;=> nil
В других Lisps, таких как Common Lisp, пустой список используется как nil
. Это известно как nil punning и является только жизнеспособным, когда пустой список является ложным. Возврат nil
здесь Clojure способ повторного ввода nil punning.
Ответ 4
Поскольку я написал комментарий, я напишу ответ. (Ответ skuro предоставляет всю информацию, но, возможно, слишком много)
- Прежде всего, я думаю, что более важные вещи должны быть в первую очередь.
-
seq
- это то, что каждый использует большую часть времени, но empty?
отлично подходит для его просто (not (seq lat))
- В Clojure '() истинно, поэтому вы хотите вернуть что-то false, если последовательность завершена.
- если в вашем случае есть только одна ветвь importend, если другая возвращает false/'() или что-то подобное, почему вы должны записать эту ветку.
when
имеет только одну ветвь, это очень полезно, если вы хотите иметь побочные эффекты. Вам не нужно использовать do
.
См. этот пример:
(если false
"()
(do (println 1) (println 2) (println 3)))
вы можете написать
(когда true (println 1) (println 2) (println 3))
Не так, но я считаю, что лучше читать.
P.S.
Не то, что есть функции с именем if-not
и when-not
, они часто бывают лучше (if (not true) ...)