Ответ 1
Потому что or
- это макрос, а не нормальная функция. Вы можете получить тот же эффект с помощью (some identity [true false])
.
Из того, что я понимаю применительно, он распаковывает список и превращает элементы в аргументы для функции.
Я вижу, что (apply + [1 2 3]) работает, как ожидалось, т.е. эквивалентно (+ 1 2 3).
Почему тогда (apply или [true false]) неверно? Разве это не эквивалентно (или истинному ложному)?
Потому что or
- это макрос, а не нормальная функция. Вы можете получить тот же эффект с помощью (some identity [true false])
.
В качестве альтернативы или вы можете использовать ( некоторый предикат coll).
clojure.core/some ([pred coll])
Возвращает первое логическое истинное значение of (pred x) для любого x из coll, иначе ноль. Одной из распространенных идиом является использование набора как пред, например, это будет return: fred if: fred находится в последовательность, иначе nil: (некоторые # {: fred} coll)
Вы можете попробовать некоторые с истинным? и ложь? предиката,
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
или - это макрос, который нельзя использовать как значение.
Создайте анонимную функцию, расширяя или в время выполнения через eval:
(apply #(eval (list* 'or %&)) [true false])
Одной из важных вещей, которую следует отметить, является модель оценки. or
коротких замыканий, поэтому: (or true :some random expression that never gets evaluated:)
никогда не оценивает последнее. or
традиционно используется как структура управления как "логическая" или "
В традиционной модели (f x y z)
оцениваются x, y и z, а f применяется к ним.
При использовании (apply f vec)
содержимое вектора не оценивается, они берутся как есть. Это наиболее четко видно с помощью вектора символов, они не оценивают в этом контексте их привязки. Тем не менее, это запутывается тем фактом, что модель w120 > для создания вектора - это то, что отличается от других lisps, [a b c d]
дает вектор, который содержит оценки символов a
, b
, c
, и d
. Контрастность большинства Lisps, где #(a b c d)
не оценивает символы и просто идентична оценке (vector 'a 'b 'c 'd)
(или фактически (apply vector '(a b c d))
).
Таким образом, даже если бы можно было применять специальные синтаксические формы, результат имел бы непрозрачную семантику. or
сначала оценивает свой первый аргумент, если true, он останавливается и возвращает это, иначе он переходит ко второму и повторяется до последнего. В случае применения аргументы уже оцениваются, если они затем оценивают второй раз? Скорее всего, это приведет к ошибке во время выполнения?
С точки зрения реализации это было бы очень выгодно для производительности, если бы синтаксис был также "объектами" и требовал бы гораздо более сложной оценочной модели. Таким образом, они не разрешаются во время выполнения, а скорее переписываются в примитивы компилятора во время компиляции.
Но именно по этой причине, когда or
используется логически, а не как структура управления, я сам считаю удобным использовать функции or/f
, and/f
, if/f
и т.д., которые истинны процедуры и оценивать все их аргументы и, следовательно, могут быть применены.