«И» против «когда» для условных

13

Это продолжение комментариев к этому ответу . Следующие биты кода кажутся эквивалентными:

(and a b)

(when a b)

Конечно, andвы можете поставить больше условий: (and a b c d)значит(when (and a b c) d)

Я склонен использовать whenтолько для выражения ветвления. Есть ли реальные различия? Лучше использовать один или другой?

У меня нет источника C Emacs под рукой; andявляется функцией C; whenэто макрос, который расширяется до if, который сам является функцией C.

Клеман
источник
«Конечно, и давайте» должно быть «Конечно,` и` позволяет », но это только изменение 2 символов и не разрешено редактировать. Там нет переопределения.
Харви

Ответы:

17

TL; DR: when о побочных эффектах, andдля чистых логических выражений.

Как вы заметили, andи whenотличаются только в синтаксисе, но в остальном полностью эквивалентны.

Однако синтаксическая разница весьма важна: whenнеявная оболочка prognохватывает все формы, кроме первого. prognявляется неотъемлемой обязательной функцией: он оценивает все, кроме самой последней формы тела, только на предмет их побочных эффектов, отбрасывая все возвращенное значение.

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

andс другой стороны, это чистая функция, основной целью которой является просмотр возвращаемых значений заданных форм аргументов: если вы явно не обернетесь prognвокруг какого-либо из его аргументов, значение каждой формы аргумента важно, и никакое значение никогда не игнорируется ,

Следовательно, настоящее различие между andи whenзаключается в стилистике: вы используете andдля чисто логических выражений и whenдля защиты от побочных эффектов форм.

Следовательно, это плохой стиль:

;; `when' used for a pure boolean expression
(let ((use-buffer (when (buffer-live-p buffer)
                    (file-exists-p (buffer-file-name buffer)))))
  ...)

;; `and' used as guard around a side-effecting form
(and (buffer-file-name buffer) (write-region nil nil (buffer-file-name buffer)))

И это хорошо

(let ((use-buffer (and (buffer-live-p buffer)
                       (file-exists-p (buffer-file-name buffer)))))
  ...)

(when (buffer-file-name buffer)
 (write-region nil nil (buffer-file-name buffer)))

Я знаю, что некоторые люди не согласны с этим и радостно используют andдля защиты от побочных эффектов, но я думаю, что это действительно плохой стиль. У нас есть эти различные формы по причине: синтаксис имеет значение . Если бы этого не произошло, мы бы все когда-либо использовали if, это единственная условная форма, которая вам действительно нужна в Emacs Lisp семантически. Все другие логические и условные формы могут быть записаны в терминах if.

lunaryorn
источник
2
IMO (то есть в стиле, который я использую) and- это забота о возвращаемом значении . Это не обязательно не об использовании побочных эффектов. Если моя программа заботится о возвращаемом значении, тогда я использую and. Если это не так, я использую when. Я использую when только для побочных эффектов, но я вполне мог бы использовать prognв одном из аргументов and. Речь идет о том вопросах , возвращаемое значение, а не о ли это только вопросы.
Дрю
5
andэто не функция ни в одном из Лиспов, о которых я знаю. В Emacs Lisp это специальная форма, в Common Lisp это макрос, просто потому, что ожидается его поведение при коротком замыкании (этого нельзя добиться с помощью функций, потому что они всегда оценивают свои аргументы).
Марк Карпов
2
@lunaryorn, да, это не совсем актуально, но это правда, поэтому я думаю, что неправильно писать, что andэто функция, когда это не так. Неважно, насколько важен этот факт для вопроса, мы всегда должны использовать правильные термины, вот и все.
Марк Карпов
2
Ну, я не думаю, что «ценность каждой формы аргумента важна» соответствует тому, что это интерпретация. Это можно было бы лучше выразить, сказав, что ни одна форма не оценивается только для исключения ее значения.
Харальд Ханче-Олсен
3
В некоторой степени ОТ, но: Разница более чем стилистическая в Лиспе, который не каламбур nilозначает «ложь», «пустой список», «пустота» и т. Д. Например, в «Схеме и ракетке» неверный результат whenесть void(то есть «нет смысла»), тогда как для andнего #f(«ложно»). Хотя это не относится к Elisp, это то, что может рассмотреть универсал Lisp.
Грег Хендершотт,
4

Позвольте мне начать с того, что (and a b)и (when a b)в вашем примере сделать то же самое: во- первых aоценивается. bоценивается , если aэто правда # .

Но and и whenиспользуются для разных вещей.

  • Вы могли бы использовать , (and a b)чтобы вернуть истинный # если ОБА aи bявляются истинными # (или не ноль); и nilиначе.

  • Вы бы использовали (when a b)или, чтобы быть более правильным,

    (when a
       ;; do something like b
       )

    когда вы хотите, чтобы код "b" выполнялся тогда и только тогда, когда aимеет значение true # .


Вот пример, где вы используете whenи andвместе:

(when (and a b)
   (do-c))

Выше, функция do-cвызывается только если оба aи bявляются правдой # .


Рекомендации для учебы

# Все ссылки на true ссылаются на логическое значение TRUE.

Каушал Моди
источник
3
andне возвращается, tесли все его аргументы не равны нулю, но значение последнего аргумента.
Значимое имя пользователя
1
К t, я имел в виду логическое значение ИСТИНА или не-ноль. Спасибо, уточню в своем ответе.
Каушал Моди
Я не думаю, что ваш ответ идет намного дальше того, что я уже сказал в вопросе; Я знаю, что оба делают, и последний пример, который вы приводите, уже появляется в моем вопросе ( (when (and a b) c)). Кроме того, часть о том, как andи whenпредполагает, что это на самом деле, как они используются в целом, но сама основа для этого вопроса был факт, что я часто вижу их использование по-разному (см., Например, ответ, который я связал в моем вопросе).
Климент
С чисто функциональной конструкцией точкой-обзор, когда для не оконечных оценок и и для прямых символов и булевой логики. Функциональное программирование нуждается в этом различении; Императивное программирование выдумывает это.
Пользователь Emacs
1
Я не думаю, что «логическое истина» более понятна, чем просто «правда».
YoungFrog