Una de las razones por las cuales los lenguajes basados en Algol fomentan las llaves en su propia línea es para alentar la adición de más líneas entre las llaves delimitadoras sin tener que mover las llaves. Es decir, si uno comienza con
if (pred)
{
printf("yes");
}
es fácil venir y agregar otra declaración entre llaves:
if (pred)
{
printf("yes");
++yes_votes;
}
Si la forma original hubiera sido
if (pred)
{ printf("yes"); }
entonces tendríamos que haber "movido" dos llaves, pero mi ejemplo está más relacionado con la última. Aquí, las llaves delimitan lo que pretende ser una secuencia de declaraciones , en su mayoría invocadas para efectos secundarios.
Por el contrario, Lisp carece de declaraciones; cada forma es expresión , dando algún valor, incluso si en algunos casos raros (pensando en Common Lisp), ese valor se elige deliberadamente para que sea "sin valores" a través de una (values)
forma vacía . Es menos común encontrar secuencias de expresiones , a diferencia de las expresiones anidadas . El deseo de "abrir una secuencia de pasos hasta el delimitador de cierre" no surge con tanta frecuencia, porque a medida que las declaraciones desaparecen y los valores devueltos se vuelven más comunes, es más raro ignorar el valor devuelto de una expresión, y por lo tanto más Es raro evaluar una secuencia de expresiones para el efecto secundario solo.
En Common Lisp, el progn
formulario es una excepción (al igual que sus hermanos):
(progn
(exp-ignored-return-1)
(exp-ignored-return-2)
(exp-taken-return))
Aquí, progn
evalúa las tres expresiones en orden, pero descarta los valores de retorno de las dos primeras. Podría imaginarse escribiendo el último paréntesis de cierre en su propia línea, pero tenga en cuenta nuevamente que, dado que la última forma es especial aquí ( aunque no en el sentido de Common Lisp de ser especial ), con un tratamiento distinto, es más probable que se agreguen nuevos expresiones en el medio de la secuencia, en lugar de simplemente "agregar otra al final", ya que las personas que llaman no se verán afectadas por ningún efecto secundario nuevo sino por un posible cambio en el valor de retorno.
Haciendo una simplificación general, los paréntesis en la mayoría de las partes de un programa Lisp delimitan argumentos pasados a funciones, al igual que en lenguajes tipo C, y no delimitan bloques de instrucciones. Por las mismas razones, tendemos a mantener los paréntesis que delimitan una llamada de función en C cerca de los argumentos, así que también hacemos lo mismo en Lisp, con menos motivación para desviarse de esa agrupación cercana.
El cierre de los paréntesis es mucho menos importante que la sangría del formulario donde se abren. Con el tiempo, uno aprende a ignorar los paréntesis y a escribir y leer por forma, al igual que los programadores de Python. Sin embargo, no dejes que esa analogía te lleve a pensar que valdría la pena eliminar los paréntesis por completo. No, ese es el debate mejor guardado comp.lang.lisp
.