«Et» vs «quand» pour les conditions

13

Il s'agit d'un suivi des commentaires sur cette réponse . Les bits de code suivants semblent être équivalents:

(and a b)

(when a b)

Bien sûr, andvous permet de mettre plus de conditions: (and a b c d)signifie(when (and a b c) d)

J'ai tendance à utiliser whenuniquement pour exprimer la ramification. Existe-t-il des différences réelles? Vaut-il mieux utiliser l'un ou l'autre?

Je n'ai pas la source C d'Emacs à portée de main; andest une fonction C; whenest une macro qui se développe en if, qui est elle-même une fonction C.

Clément
la source
"Bien sûr et permet" devrait être "Bien sûr` et permet ", mais ce n'est qu'un changement de 2 caractères et ce n'est pas une modification autorisée. Il n'y a pas de priorité.
Harvey

Réponses:

17

TL; DR: when concerne les effets secondaires, andconcerne les expressions booléennes pures.

Comme vous l'avez remarqué, andet whenne diffèrent que par la syntaxe, mais sont par ailleurs entièrement équivalents.

La différence syntaxique est assez importante, cependant: whenenveloppe un implicite prognautour de toutes les formes sauf les premiers arguments. prognest une caractéristique intrinsèquement impérative: il évalue tous, sauf la toute dernière forme corporelle, pour leurs effets secondaires uniquement, en rejetant la valeur qu'ils ont renvoyée.

En tant que tel, il whens'agit également d'une forme impérative: son objectif principal est d'envelopper les formes à effets secondaires, car seule la valeur de la toute dernière forme importe réellement pour le corps.

andd'autre part, est une fonction pure, dont le but principal est de regarder les valeurs de retour des formes d'argument données: à moins que vous ne progncontourniez explicitement l' un de ses arguments, la valeur de chaque forme d'argument est importante et aucune valeur n'est jamais ignorée .

Par conséquent, la vraie différence entre andet whenest stylistique: vous utilisez andpour des expressions booléennes pures et whenpour mettre une garde autour des formes à effets secondaires.

Par conséquent, ce sont de mauvais style:

;; `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)))

Et ce sont bien:

(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)))

Je sais que certaines personnes sont en désaccord à ce sujet et utilisent heureusement andpour protéger les effets secondaires, mais je pense que c'est vraiment un mauvais style. Nous avons ces différentes formes pour une raison: la syntaxe est importante . Si ce n'était pas le cas, nous n'utiliserions que jamais if, qui est la seule forme conditionnelle dont vous avez vraiment besoin dans Emacs Lisp sémantiquement. Toutes les autres formes booléennes et conditionnelles peuvent être écrites en termes de if.

lunaryorn
la source
2
IMO (c'est-à-dire, dans le style que j'utilise), andconsiste à se soucier de la valeur de retour . Il ne s'agit pas nécessairement d'utiliser des effets secondaires. Si mon programme se soucie de la valeur de retour, j'utilise and. Si ce n'est pas le cas, je l'utilise when. IOW, je l'utilise when uniquement pour les effets secondaires, mais je pourrais bien utiliser un progndans l'un des arguments pour and. Il s'agit de savoir si la valeur de retour est importante, pas de savoir si elle est seule importante.
Drew
5
andn'est pas une fonction dans n'importe quel Lisp que je connaisse. Dans Emacs Lisp, c'est une forme spéciale, dans Common Lisp, c'est une macro, simplement parce qu'il devrait avoir un comportement de court-circuit (impossible à réaliser avec les fonctions, car elles évaluent toujours leurs arguments).
Mark Karpov
2
@lunaryorn, Oui, ce n'est pas vraiment pertinent, mais c'est vrai, donc je pense qu'il est incorrect d'écrire que andc'est une fonction, alors que ce n'est pas le cas. Peu importe la pertinence du fait pour la question, nous devons toujours utiliser des termes corrects, c'est tout.
Mark Karpov
2
Eh bien, je ne pense pas que «la valeur de chaque forme d'argument soit importante» soit cohérente avec cette interprétation. Cela aurait pu être mieux exprimé en disant qu’aucune forme n’est évaluée uniquement pour avoir sa valeur jetée.
Harald Hanche-Olsen
3
Un peu OT, mais: La différence est plus que stylistique en Lisps qui ne punit pas nilpour signifier tout "faux", "la liste vide", "vide", etc. Par exemple dans Scheme et Racket le résultat non véridique de whenest void(c'est-à-dire "pas de sens") alors que pour andlui est #f("faux"). Bien que ce soit N / A pour Elisp, c'est quelque chose qu'un généraliste Lisp pourrait considérer.
Greg Hendershott
4

Permettez-moi de commencer en disant cela (and a b)et (when a b)dans votre exemple, faites la même chose: le premier aest évalué. best évalué si aest vrai # .

Mais and et whensont utilisés pour différentes choses.

  • Vous utiliseriez (and a b)pour renvoyer true # si LES DEUX aet bsont true # (ou non nul); et nilautrement.

  • Vous utiliseriez (when a b)ou pour être plus correct,

    (when a
       ;; do something like b
       )

    lorsque vous voulez que le code "b" s'exécute si et seulement si aest vrai # .


Voici un exemple où vous utilisez whenet andensemble:

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

Ci-dessus, la fonction do-cest appelée UNIQUEMENT si LES DEUX aet bsont vraies # .


Références pour l'étude

# Toutes les références à true se réfèrent à la valeur booléenne TRUE.

Kaushal Modi
la source
3
andne renvoie pas tsi tous ses arguments sont non nuls, mais la valeur du dernier argument.
Nom d'utilisateur significatif
1
Par t, je voulais dire le booléen VRAI ou non nul. Merci, je vais clarifier cela dans ma réponse.
Kaushal Modi
Je ne pense pas que votre réponse va beaucoup plus loin que ce que j'ai déjà dit dans la question; Je sais ce que font les deux, et le dernier exemple que vous donnez apparaît déjà dans ma question ( (when (and a b) c)). De plus, la partie sur la façon dont andet whensuggère que c'est en fait comment ils sont utilisés en général, mais la base même de cette question était le fait que je les vois souvent utilisés différemment (voir par exemple la réponse à laquelle j'ai lié dans ma question).
Clément
D'un point de vue de construction purement fonctionnelle, quand est pour les évaluations non terminales et et est pour les symboles directs et la logique booléenne. La programmation fonctionnelle a besoin de cette distinction; la programmation impérative fausse ceci.
Emacs User
1
Je ne pense pas que "boolean true" soit plus clair que "true".
YoungFrog