¿Cuándo / por qué debo usar progn?


19

He visto que prognse usa mucho mientras navego por los archivos de configuración de usuarios experimentados de Emacs. Encontré esta buena explicación deprogn , pero lo que realmente me interesa es, ¿cuál es el beneficio de usar esta función? Tomemos, por ejemplo, este fragmento (tomado de la configuración de Sacha Chua ):

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

¿Hay alguna diferencia importante entre la configuración anterior y esta?

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t))

Siento que el primer ejemplo es de alguna manera más limpio, a pesar de que tiene más sintaxis, y mi intuición es que podría haber algún tipo de aumento de rendimiento por el uso progn, pero no estoy seguro. Gracias por cualquier idea!


77
En este caso particular no hay diferencia: use-packageenvolverá un prognalrededor de sus formularios: config si falta. Pruébelo: puede poner el punto al final de una (use-package ...)y llamar M-x pp-macroexpand-last-sexppara ver cómo se expande la macro. Verá que es idéntico para estos dos ejemplos.
glucas

Un ejemplo donde prognse necesita: emacs.stackexchange.com/questions/39172/…
npostavs

Respuestas:


11

prognse usa típicamente cuando se trata de macros. Algunas macros ( use-packagees una macro, la última que verifiqué) aceptan solo 1 formulario , mientras que otros consumen todos los formularios restantes .

progn se usa en el primer caso para convertir una secuencia de formas en una sola forma.

En sus ejemplos, el primero usa progny, por lo tanto, hay 1 formulario después :config. En el segundo, hay 3 formas . Si la use-packagemacro solo espera 1 formulario siguiente :config, causará un error.

Vale la pena señalar que el uso prognfunciona en ambos casos, mientras que omitirlo solo funciona si la macro acepta múltiples formas. Como resultado de esto, algunas personas prefieren simplemente usar siempre progn, porque siempre funcionará.


15
Realmente no tiene nada que ver con las macros. Algunas funciones y macros tienen el llamado "implícito progn", lo que significa que aceptan cualquier número de sexps como argumentos separados y los evalúan en secuencia. Otros no lo hacen, y en cambio esperan / permiten solo un único argumento en el que es posible que desee evaluar múltiples sexps en secuencia. Eso es todo progn: le permite proporcionar un único sexp que, cuando se evalúa, evalúa los argumentos de sexp prognen secuencia. Comparar (if true (progn a b c))con (when true a b c). En ambos casos, a, b, y cson evaluados de forma secuencial.
Dibujó el


44
No estoy de acuerdo con que el 99% de los casos de uso sean para macros, etc. Cualquier función o macro se puede pasar a un prognsexp que contiene múltiples sexps que se evalúan por sus efectos secundarios, antes de devolver el resultado del último de estos. Realmente no tiene nada que ver con las macros. Las macros "como ejemplo" están bien. Dar la impresión que prognexiste para las macros, y que el 99% de su uso es para macros, es engañoso, en mi opinión. prognse trata de palear una secuencia de evaluaciones en un solo sexp (para ajustarse a un argumento esperado), y por lo tanto se trata de efectos secundarios .
Dibujó el

55
1. prognse introdujo en Lisp 1.5 (ver sección La característica del programa ), en 1962, mucho antes de que se agregaran macros a Lisp. El propósito es evaluar secuencialmente las expresiones para sus efectos secundarios. 2. Vea progncómo Emacs se presenta progna los programadores de Elisp. Vea el zap-to-charcódigo para un caso de uso simple.
Dibujó el

2
Podemos estar de acuerdo en no estar de acuerdo. Mi punto es que noprogn tiene nada que ver con las macros. Su propósito es, por supuesto, " pasar múltiples formas como una sola forma " (sus palabras), ya sea a una función o una macro o una forma especial, pero también a " Evaluar las formas del CUERPO secuencialmente y devolver el valor de la última " (cadena de documentación ) Ahora como siempre ("estos días", de hecho!). Una evaluación ordenada es importante solo para los efectos secundarios, obviamente. Un caso de uso dado (macro o no) puede o no preocuparse por el orden de evaluación, pero eso es irrelevante. Y Emacs Lisp no es excepcional de ninguna manera a este respecto.
Dibujó el

10

La razón más importante para el progn se describe en la primera línea de la documentación del progn (énfasis agregado):

progn es una forma especial que hace que cada uno de sus argumentos se evalúe en secuencia y luego devuelve el valor del último.

Apéndice:

Sin progn , la secuencia no está garantizada, especialmente si las expresiones posteriores dependen de los efectos secundarios o los valores de retorno de las expresiones anteriores. progn impone la secuencia de ejecución igual que la secuencia de texto. Ayuda a no confundir ejecución con análisis. Este comportamiento se remonta a los fundamentos de las estructuras de control de lisp y la programación funcional. Aquí hay un extracto (énfasis agregado) del manual de referencia de lisp :

Las estructuras de control integradas son formas especiales ya que sus subformularios no se evalúan necesariamente o no se evalúan secuencialmente .

¿ Progn aumenta el rendimiento?

Análisis de rendimiento, no. Ejecución de ejecución, no. En el mejor de los casos, puede igualar pero nunca aumentar mágicamente el rendimiento.

¿Cuándo se usa progn ?

... con mayor frecuencia dentro de una protección de desenrollado, y, o , o en la parte de un if .


No estoy seguro de por qué es tan importante. Emacs siempre evalúa secuencialmente.
lunaryorn

2
@lunaryorn ver la respuesta actualizada.
Usuario de Emacs el

No estoy seguro de entender tu edición. Naturalmente, hay formas especiales con un orden de evaluación diferente (por ejemplo if), pero el orden de evaluación normal (por ejemplo, formas de nivel superior, cuerpos de funciones, etc.) es textual. Claro, hasta cierto punto eso es implícito progn, pero generalmente no es lo que usa progn en su propio código.
lunaryorn

Creo que el nodo manual de Elisp que enlazas (elisp) Sequencinglo dice todo.
Albahaca

10

Una mejor manera de entender lo que prognes es comparándolo con la familia: prog1y prog2. El no 1o 2parte del nombre se refiere a la declaración de la lista cuyo resultado que le interesa. En otras palabras, progndevolverá el resultado de la última declaración que contiene, mientras que prog1devolverá el primero, y similar para prog2.

Hoy en día, esta funcionalidad parece un poco incómoda, ya que aprendemos a esperar que el programa regrese en la última declaración o a indicarle explícitamente qué devolver. Por lo tanto prog1y prog2rara vez se utilizan. Sin embargo, si lo piensa, tiene sentido, y así es cómo:

Diferentes lenguajes de programación utilizan diferentes estrategias para describir su semántica. La familia Lisp solía estar estrechamente vinculada a la semántica denotacional. Sin entrar en muchos detalles, este tipo de semántica tiene una dificultad particular con algo que crecimos conocer como "declaraciones", que no son "expresiones". Los significados del código generalmente se piensan en términos de combinaciones de funciones, mientras que una "declaración" que ni siquiera se puede describir como una función (ya que no evalúa nada) es, por lo tanto, difícil de manejar. Sin embargo, dado que Lisp permite efectos secundarios, a veces un programador querría usar una expresión sin usar su valor de manera que no afecte la expresión que le sigue. Y aquí es donde progXentra la familia.

En lenguajes tipo C, esta característica a veces se conoce como punto de secuencia (es decir, ;y ,por ejemplo). prognes tan esencial para los lenguajes de tipo Lisp como lo ;es para los lenguajes de tipo C. Es una característica fundamental del lenguaje que no se puede reemplazar fácilmente. Sin embargo, a diferencia de los lenguajes de estilo C, Lisp tiende a construir abstracciones sintácticas al ocultar por completo la sintaxis del nivel inferior. Y esta es quizás la razón por la que no se prognusa con tanta frecuencia, sin embargo, es uno de los bloques de construcción importantes, cuando se trata de construir abstracciones de lenguaje de alto nivel (sa macros).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.