"Y" vs "cuándo" para condicionales

13

Este es un seguimiento de los comentarios sobre esta respuesta . Los siguientes bits de código parecen ser equivalentes:

(and a b)

(when a b)

Por supuesto andte permite poner más condiciones: (and a b c d)significa(when (and a b c) d)

Tiendo a usar whensolo para expresar ramificaciones. ¿Hay diferencias reales? ¿Es mejor usar uno u otro?

No tengo la fuente C de Emacs a la mano; andes una función C; whenes una macro que se expande if, que en sí misma es una función C.

Clemente
fuente
"Por supuesto y deja" debería ser "Por supuesto` y` deja ", pero eso es solo un cambio de 2 caracteres y no es una edición permitida. No hay anulación.
Harvey

Respuestas:

17

TL; DR: when se trata de efectos secundarios, andes para expresiones booleanas puras.

Como se ha notado, andy whensólo se diferencian en la sintaxis, pero por lo demás está totalmente equivalentes.

Sin embargo, la diferencia sintáctica es bastante importante: whenenvuelve un implícito prognalrededor de todas las formas excepto el primer argumento. prognes una característica inherentemente imperativa: evalúa todas las formas del cuerpo, excepto la última, solo por sus efectos secundarios, descartando cualquier valor que hayan devuelto.

Como tal, también whenes una forma imperativa: su propósito principal es envolver las formas de efectos secundarios, porque solo el valor de la última forma realmente importa para el cuerpo.

andPor otro lado, es una función pura, cuyo objetivo principal es mirar los valores de retorno de las formas de argumento dadas: a menos que envuelva explícitamente prognalguno de sus argumentos, el valor de cada forma de argumento es importante y nunca se ignora ningún valor .

Por lo tanto, la verdadera diferencia entre andy whenes estilística: se usa andpara expresiones booleanas puras y whenpara proteger las formas de efectos secundarios.

Por lo tanto, estos son mal estilo:

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

Y estos son buenos:

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

Sé que algunas personas no están de acuerdo con esto, y felizmente lo usan andpara proteger los efectos secundarios, pero creo que este es un estilo realmente malo. Tenemos estas diferentes formas por una razón: la sintaxis importa . Si no fuera así, todos lo usaríamos alguna vez if, que es la única forma condicional que realmente necesita semánticamente en Emacs Lisp. Todas las demás formas booleanas y condicionales se pueden escribir en términos de if.

Lunaryorn
fuente
2
IMO (es decir, en el estilo que uso), andse trata de preocuparse por el valor de retorno . No se trata necesariamente de usar efectos secundarios. Si mi programa se preocupa por el valor de retorno, entonces lo uso and. Si no es así, lo uso when. IOW, when solo lo uso para efectos secundarios, pero bien podría usar prognuno en uno de los argumentos para and. Se trata de si el valor de retorno importa, no de si solo importa.
Dibujó el
55
andno es una función en ningún Lisp que conozco. En Emacs Lisp es una forma especial, en Common Lisp es una macro, simplemente porque se espera que tenga un comportamiento de cortocircuito (imposible de lograr con funciones, porque siempre evalúan sus argumentos).
Mark Karpov
2
@lunaryorn, sí, no es realmente relevante, pero es cierto, así que creo que es incorrecto escribir que andes una función, cuando no lo es. No importa cuán relevante sea el hecho para la pregunta, siempre debemos usar términos correctos, eso es todo.
Mark Karpov
2
Bueno, no creo que "el valor de cada forma de argumento sea importante" sea consistente con lo que esa interpretación. Podría haberse expresado mejor diciendo que no se evalúa ninguna forma solo para descartar su valor.
Harald Hanche-Olsen
3
Algo OT, pero: la diferencia es más que estilística en Lisps que no hace juego nilde palabras para significar todo "falso", "la lista vacía", "vacío", etc. Por ejemplo, en Scheme and Racket, el resultado no verdadero de whenes void( es decir, "sin significado") mientras que para andesto es #f("falso"). Aunque esto es N / A para Elisp, es algo que un generalista de Lisp podría considerar.
Greg Hendershott
4

Permítanme comenzar diciendo eso (and a b)y, (when a b)en su ejemplo, hagan lo mismo: Primero ase evalúa. bse evalúa si aes verdadero # .

Pero and y whense utilizan para diferentes cosas.

  • Usted usaría (and a b)para devolver el verdadero # si AMBOS ay bson verdaderos # (o no-nulo); y de lo nilcontrario

  • Usarías (when a b)o para ser más correcto,

    (when a
       ;; do something like b
       )

    cuando quiere que el código "b" se ejecute si y solo si aes verdadero # .


Aquí hay un ejemplo donde usas wheny andjuntos:

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

Arriba, la función do-cse llama SOLO si AMBOS ay bson verdaderos # .


Referencias para estudio

# Todas las referencias a verdadero se refieren a Boolean TRUE.

Kaushal Modi
fuente
3
andno regresa tsi todos sus argumentos son no nulos, sino el valor del último argumento.
Nombre de usuario significativo
1
Por t, me refería al booleano VERDADERO o no nulo. Gracias, aclararé eso en mi respuesta.
Kaushal Modi
No creo que su respuesta vaya mucho más allá de lo que ya dije en la pregunta; Sé lo que hacen ambos, y el ejemplo final que das ya aparece en mi pregunta ( (when (and a b) c)). Además, la parte sobre cómo andy whensugiere que en realidad así es como se usan en general, pero la base misma de esta pregunta fue el hecho de que a menudo veo que se usan de manera diferente (ver, por ejemplo, la respuesta a la que me vinculé en mi pregunta).
Clément
Desde un punto de vista de construcción puramente funcional, cuando es para evaluaciones sin terminación y es para símbolos directos y lógica booleana. La programación funcional necesita esta distinción; programación imperativa fudge esto lejos.
Usuario de Emacs el
1
No creo que "boolean true" sea más claro que simplemente "true".
YoungFrog