"І" проти "коли" для умов


13

Це супроводження коментарів до цієї відповіді . Наступні біти коду здаються еквівалентними:

(and a b)

(when a b)

Звичайно, andдозволяє поставити більше умов: (and a b c d)засоби(when (and a b c) d)

Я схильний використовувати whenлише для вираження розгалуження. Чи є фактичні відмінності? Чи краще використовувати те чи інше?

Я не маю під рукою джерела C Emacs; andє функцією С; when- це макрос, який розширюється до if, який сам по собі є функцією C.


"Звичайно і дозволяє" має бути "Звичайно` і `дозволяє", але це лише зміна двох символів і не дозволяється редагувати. Переоцінки немає.
Харві

Відповіді:


18

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.


2
IMO (тобто в стилі, який я використовую) - andце турбота про повернене значення . Це не обов’язково не про використання побічних ефектів. Якщо моя програма піклується про повернене значення, то я використовую and. Якщо це не так, я використовую when. IOW, я використовую when лише для побічних ефектів, але я цілком можу використовувати a prognв одному з аргументів для and. Йдеться про те, чи має значення значення повернення, а не про те, чи має значення воно одне .
Дрю

5
and- це не функція, яку я знаю. У Emacs Lisp це особлива форма, у Common Lisp це макрос, просто тому, що, як очікується, він матиме коротке замикання (неможливо досягти за допомогою функцій, оскільки вони завжди оцінюють свої аргументи).
Марк Карпов

2
@lunaryorn, Так, це не дуже актуально, але це правда, тому я думаю, що неправильно писати, що andце функція, коли це не так. Не має значення, наскільки актуальним є питання, ми завжди повинні використовувати правильні терміни, ось і все.
Марк Карпов

2
Ну, я не думаю, що «значення кожної форми аргументу є важливим» відповідає тому, що трактує. Це можна було б краще виразити, сказавши, що жодна форма не оцінюється лише для того, щоб її значення було викинуто.
Харальд Ханш-Олсен

3
Дещо OT, але: Різниця є більш ніж стилістичною в Lisps, які не кажуть, nilщоб означати всі "хибні", "порожній список", "недійсні" і т. Д. Наприклад, в Scheme and Racket, неістинний результат whenє void(тобто "немає значення"), тоді як для andнього #f("помилково"). Незважаючи на те, що для Еліспа це не відповідає вимогам, це може врахувати загальний експерт Lisp.
Грег Хендершот

4

Дозвольте розпочати з того, що (and a b)і (when a b)у вашому прикладі зробіть те саме: Спочатку aоцінюється. bоцінюється, якщо aце істина # .

Але and і whenвикористовуються для різних речей.

  • Ви б використали (and a b)для повернення true # якщо BOTH aі bє істинним # (або non-nil); і в nilіншому випадку.

  • Ви б використовували (when a b)або, щоб бути більш правильним,

    (when a
       ;; do something like b
       )
    

    коли ви хочете, щоб код "b" виконувався, якщо і лише тоді, якщо aце істинно # .


Ось приклад, коли ви використовуєте разом whenі andразом:

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

Вище, функція do-cназивається ТОЛЬКО, якщо БОЛЬНА, aі bє істиною # .


Список літератури для вивчення

# Усі посилання на істинні стосуються булевої ІСТИНИ.


3
andне повертається, tякщо всі його аргументи не є нульовими, але значення останнього аргументу.
Значуще ім’я користувача

1
До t, я мав в виду логічне значення ІСТИНА або НЕ-нуль. Дякую, я уточню це у своїй відповіді.
Каушал Моді

Я не думаю, що ваша відповідь іде значно далі, ніж те, про що я вже говорив у запитанні; Я знаю, що обидва роблять, і останній приклад, який ви даєте, вже з’являється в моєму запитанні ( (when (and a b) c)). Крім того, частина про те, як andі whenнапрошується, що це насправді, як вони використовуються в цілому, але саме основою цього питання було те, що я часто бачу їх використання по-різному (див., Наприклад, відповідь, з яким я пов’язаний у своєму запитанні).
Clément

З чисто функціональної конструкцією точкою-огляд, коли для НЕ кінцевих оцінок і і для прямих символів і булевої логіки. Функціональне програмування потребує цього розрізнення; імперативне програмування роздуває це.
Користувач Emacs

1
Я не думаю, що "булева правда" є більш зрозумілою, ніж просто "правда".
YoungFrog
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.