Formateo de código Lisp
clojure code-formatting (5)
Cuando tienes 10 paréntesis para cerrar, se vuelve realmente torpe.
Cuando solía programar Lisp, dejaba un espacio entre los paréntesis de cierre para abrir paréntesis en la misma línea y el resto, para simplificar el recuento, así:
(if (= a something) (if (= b otherthing) (foo) ))
Supongo que en estos días ya no es necesario, ya que los editores son más útiles.
Una de las personas que se tomaron el tiempo para comentar mi otra pregunta sobre la sintaxis de Clojure / LISP señaló que no había escrito mi código de muestra de la manera estándar de LISP. Así que tuvo la amabilidad de reescribir el fragmento de código y es una gran ayuda. Pero planteó otra pregunta en mi mente. Por qué esto:
(if (= a something)
(if (= b otherthing)
(foo)))
que es el formato LISP estándar ser preferible a esta forma:
(if (= a something)
(if (= b otherthing)
(foo)
)
)
que es la forma en que habría formateado ingenuamente este código debido a mi fondo de desarrollo C ++. Me pregunto si hay algún beneficio para el último formato o es solo un estándar arraigado (como un teclado QWERTY). No estoy tratando de ser argumentativo, es difícil para mí entender por qué la primera forma sería preferible. La segunda forma me ayuda a ver la estructura del código más fácilmente.
La forma en que se sangra el código Lisp es similar al espacio en blanco significativo en Python, excepto que, por supuesto, es opcional. La regla básica es que coloque los elementos en una lista uno debajo del otro verticalmente si no están en la misma línea.
(a (b (c (d e)
(f g))
(h i j))
(k l m n))
Sin siquiera mirar el paréntesis, puede ver que (de)
y (fg)
son parámetros para c
, (c (de) (fg))
y (hij)
son parámetros para b
, y (b (c (de) (fg)) (hij))
y (klmn)
son parámetros para a
.
Con su ejemplo, debería formatearse más correctamente de la siguiente manera:
(if (= a something)
(if (= b otherthing)
(foo)))
^ ^
notice how they line up
Ahora que el nivel de sangría se vuelve significativo, ya no tiene que depender de un paréntesis de equilibrio para obtener esa información, y dado que es más compacto ponerlos en la misma línea que el enunciado de cierre, eso es lo que hacen los celadores. Por supuesto, no es necesario que el código Lisp se formatee de esta manera, pero es una convención bastante estándar que las personas usan y en la que pueden confiar.
Los paréntesis de cierre en líneas adicionales realmente no ayudan a ver la estructura del código, porque puede obtener la misma información del nivel de sangría. Sin embargo, la segunda forma ocupa casi el doble de líneas, lo que le obliga a desplazarse con más frecuencia al leer el código.
Y si necesita inspeccionar los paréntesis anidados más de cerca, un editor que resalte el paréntesis correspondiente lo ayudará. Esto también será más fácil cuando el paréntesis correspondiente no esté demasiado lejos.
Si las expresiones son demasiado largas y complicadas para ser leídas fácilmente, también puede ser una señal de que debe extraer parte de la funcionalidad en una función separada.
La respuesta simple es que tu camino no es la forma en que la guapa impresora de Lisp hace las cosas. Tener un FORMATO VERDADERO siempre es una buena cosa para el código, y la macro de pprint le da ese formato integrado en el lenguaje.
Por supuesto, debido a que existe la macro de pprint, no es estrictamente necesario que siga el formato de código estándar, porque las personas pueden simplemente ejecutar su código a través de pprint y obtener lo que están acostumbrados. Sin embargo, dado que todos los demás usan pprint, o lo aproximan manualmente, tendrá dificultades para leer el código si no lo hace de la misma manera, y no tiene una macro fácil que convierta su código en su preferido formato.
Puede reformatear el código Lisp con el paquete Sreafctor: Homepage .
Algunas demostraciones
- Formateo de toda la demostración de búfer en Clojure. Probé en un archivo Clojure con 10k líneas y tardé alrededor de 10 segundos en formatear todo (un tiempo significativo dedicado a la indentación, no al reordenamiento del código).
- Formateo de toda la demostración de búfer en Emacs Lisp
- Transformar entre una línea <-> demostración de Multiline
Comandos disponibles:
-
srefactor-lisp-format-buffer
: formatear el buffer completo -
srefactor-lisp-format-defun
: el cursor de defunción actual del formato está en -
srefactor-lisp-format-sexp
: formato en el que se encuentra el cursor sexp actual. -
srefactor-lisp-one-line
: convierte el sexp actual del mismo nivel en una línea; con el argumento prefijo, gire recursivamente todos los sexps internos en una línea.
Los comandos de formateo también se pueden usar en Common Lisp y Scheme.
Si hay algún problema, envíe un informe de problema y lo arreglaré con gusto.