Почему (не применимо или [true false]) не работает в Clojure? - PullRequest
20 голосов
/ 04 июня 2010

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

Я вижу, что (apply + [1 2 3]) работает как положено, то есть: это эквивалентно (+ 1 2 3).

Почему тогда (применять или [истинно неверно]) неверно? Разве это не эквивалентно (или истинно ложно)?

Ответы [ 5 ]

19 голосов
/ 04 июня 2010

Потому что or - это макрос, а не обычная функция. Вы можете получить тот же эффект с (some identity [true false]).

4 голосов
/ 04 июня 2010

В качестве альтернативы или вы можете использовать ( некоторый предикат coll).

clojure.core / some ([pred coll])
Возвращает первое логическое истинное значение of (pred x) для любого x в coll, иначе ноль. Одна общая идиома - использовать набор как пред, например это будет return: fred, если: fred находится в последовательность, иначе ноль: (немного # {: fred} coll)

3 голосов
/ 04 июня 2010

Можете попробовать с истиной? и ложь? предикаты,


user=> (some true? [true false false])
true
user=> (not (some true? [true false false]))
false
user=> (some false? [true false false])
true
user=> (not (some false? [true false false]))
false

0 голосов
/ 05 июня 2010

Одной из важных вещей, которые следует отметить, является модель оценки. or короткое замыкание, поэтому: (or true :some random expression that never gets evaluated:) никогда не оценивает последнее. or традиционно используется столько же, сколько управляющая структура, как «логическое или».

В традиционной модели (f x y z), x, y и z оцениваются, и к ним применяется f.

При использовании (apply f vec) содержимое вектора не оценивается, оно принимается как есть. Это наиболее четко видно по вектору символов, они не оценивают в этом контексте свои привязки. Однако это скрыто тем фактом, что модель Clojure для создания вектора несколько отличается от других lisps, [a b c d] дает вектор, который содержит оценки символов a, b, c и d. В отличие от большинства Лиспов, где #(a b c d) не оценивает символы, а просто идентичен оценке (vector 'a 'b 'c 'd) (или фактически (apply vector '(a b c d))).

Таким образом, даже если бы можно было применять специальные синтаксические формы, его результат имел бы непрозрачную семантику. or сначала оценивает свой первый аргумент, если он равен true, останавливается и возвращает его, иначе он переходит ко второму и повторяется до последнего. В случае применения, аргументы уже все оценены, должны ли они оцениваться во второй раз? Скорее всего, что приведет к ошибке во время выполнения?

С точки зрения реализации, было бы очень сильно снизить производительность, если бы синтаксис был также «объектом» и потребовал бы гораздо более сложной модели оценки. Поэтому они не разрешаются во время выполнения, а переписываются в примитивы компилятора во время компиляции.

Но именно по этой причине, когда or используется логически, а не как управляющая структура, мне самому удобно иметь в наличии функции or/f, and/f, if/f и так далее, которые являются истинными процедуры и оценить все свои аргументы и, следовательно, могут быть применены.

0 голосов
/ 04 июня 2010

или - это макрос, который нельзя использовать в качестве значения.

Создание анонимной функции с расширением или при времени выполнения через eval:

(apply #(eval (list* 'or %&)) [true false])
...