Quando / perché dovrei usare progn?


19

Ho visto prognessere usato parecchio mentre sfoglio i file di configurazione degli utenti Emacs esperti. Ho trovato questa bella spiegazione diprogn , ma ciò di cui sono davvero curioso è, qual è il vantaggio di usare questa funzione? Prendi ad esempio questo frammento (tratto dalla configurazione di 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)))

C'è qualche grande differenza tra la configurazione sopra e questa?

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

Sento che il primo esempio è in qualche modo più pulito, anche se ha più sintassi, e la mia intuizione è che potrebbe esserci qualche tipo di aumento delle prestazioni dall'uso progn, ma non ne sono sicuro. Grazie per eventuali approfondimenti!


7
In questo caso particolare non c'è differenza: use-packageavvolgerà un progntuo: config form se manca. Provalo: puoi mettere il punto alla fine di a (use-package ...)e chiamare M-x pp-macroexpand-last-sexpper vedere come viene espansa la macro. Vedrai che è identico per questi due esempi.
glucas,

Un esempio in cui prognè necessario: emacs.stackexchange.com/questions/39172/…
npostavs

Risposte:


11

prognviene generalmente utilizzato quando si ha a che fare con le macro. Alcune macro ( use-packageè una macro, ho controllato l'ultima volta) accettano solo 1 modulo , mentre altri consumano tutti i moduli rimanenti .

progn è usato nel primo caso per trasformare una sequenza di forme in una singola forma.

Nei tuoi esempi, il primo usa progne quindi c'è 1 modulo dopo :config. Nel secondo, ci sono 3 forme . Se la use-packagemacro prevede solo 1 modulo seguente :config, causerà un errore.

Vale la pena notare che l'utilizzo prognfunziona in entrambi i casi, mentre l'omissione funziona solo se la macro accetta più moduli. Di conseguenza, alcune persone preferiscono semplicemente utilizzare sempre progn, perché funzionerà sempre.


15
Non ha davvero nulla a che fare con le macro. Alcune funzioni e macro hanno un cosiddetto "implicito progn", nel senso che accettano qualsiasi numero di sexp come argomenti separati e li valutano in sequenza. Altri no, e invece si aspettano / consentono solo un singolo argomento in cui potresti voler valutare più sexp in sequenza. Questo è tutto progn: ti consente di fornire un singolo sexp che quando valutato valuta il sexp su cui si discute prognin sequenza. Confronta (if true (progn a b c))con (when true a b c). In entrambi i casi, a, b, e cvengono valutati in sequenza.
Ha


4
Non sono d'accordo sul fatto che il 99% dei casi d'uso riguardi le macro, ecc. A qualsiasi funzione o macro può essere passato un prognsexp che contiene più sexp che vengono valutati per i loro effetti collaterali, prima di restituire il risultato dell'ultimo di questi. Non ha davvero nulla a che fare con le macro. Le macro "come esempio" vanno bene. Dare l'impressione che prognesiste per le macro e che il 99% del suo utilizzo è per le macro, è fuorviante, IMO. prognsi tratta di spalare una sequenza di valutazioni in un singolo sexp (per adattarsi a un dato argomento atteso), e quindi di effetti collaterali .
Estratto il

5
1. è prognstato introdotto in Lisp 1.5 (vedere la sezione The Program Feature ), nel 1962, molto prima che le macro fossero aggiunte a Lisp. Lo scopo è valutare sequenzialmente le espressioni per i loro effetti collaterali. 2. Guarda progncome Emacs stesso introduce i prognprogrammatori Elisp. Vedi il zap-to-charcodice per un caso d'uso semplice.
Estratto il

2
Possiamo convenire che non concordiamo. Il mio punto è che nonprogn ha nulla a che fare con le macro. Il suo scopo è ovviamente " passare più forme come una singola forma " (le tue parole) - sia a una funzione o una macro o una forma speciale, ma anche a " Eval BODY form sequenzialmente e restituire il valore dell'ultima " (doc string ). Ora come sempre ("questi giorni", anzi!). Una valutazione ordinata è importante solo per gli effetti collaterali, ovviamente. Un determinato caso d'uso (macro o meno) potrebbe o meno interessarsi all'ordine di valutazione, ma ciò è irrilevante. E Emacs Lisp non è eccezionale in alcun modo al riguardo.
Estratto il

10

Il motivo più importante per progn è descritto nella prima riga della documentazione progn (enfasi aggiunta):

progn è una forma speciale che fa valutare ciascuno dei suoi argomenti in sequenza e quindi restituisce il valore dell'ultimo.

Addendum:

Senza progn , la sequenza non è garantita, specialmente se le espressioni successive dipendono dagli effetti collaterali o dai valori di ritorno delle espressioni precedenti. progn impone la sequenza di esecuzione come la sequenza testuale. Aiuta a non confondere l'esecuzione con l'analisi. Questo comportamento risale ai fondamenti delle strutture di controllo lisp e della programmazione funzionale. Ecco un estratto (enfasi aggiunta) dal manuale di riferimento lisp :

Le strutture di controllo integrate sono forme speciali poiché le loro sottomaschere non sono necessariamente valutate o non valutate in sequenza .

Fa progn migliorare le prestazioni?

Analisi delle prestazioni, no. Performance di esecuzione, no. Nella migliore delle ipotesi può essere uguale ma mai aumentare magicamente le prestazioni.

Quando viene usato progn ?

... il più delle volte all'interno di un unfind-protect, e, o , o nella parte di allora di un if .


Non sono sicuro del perché sia ​​così importante. Emacs valuta sempre in sequenza.
lunaryorn,

2
@lunaryorn vedi la risposta aggiornata.
Emacs User

Non sono sicuro di aver compreso la tua modifica. Naturalmente esistono moduli speciali con un diverso ordine di valutazione (ad es. if), Ma il normale ordine di valutazione (ad es. Moduli di livello superiore, organi di funzione, ecc.) È testuale. Certo, in una certa misura questo è implicito progn, ma di solito non è quello che usi progn nel tuo codice.
lunaryorn,

Penso che il nodo manuale Elisp a (elisp) Sequencingcui si collega dice tutto.
Basilio,

10

Un modo migliore per capire cos'è prognè confrontandolo con la famiglia: prog1e prog2. La no il 1o 2parte del nome sta per il comunicato della lista il cui risultato che ti interessa. In altre parole, prognrestituirà il risultato dell'ultima dichiarazione che contiene, mentre prog1tornerà il primo, e simile per prog2.

Oggi questa funzionalità sembra un po 'imbarazzante dal momento che impariamo a aspettarci che il programma ritorni nell'ultima affermazione, o ad istruire esplicitamente cosa restituire. Quindi prog1e prog2sono usati molto di rado. Tuttavia, se ci pensate, ha senso, ed ecco come:

Diversi linguaggi di programmazione usano strategie diverse per descrivere la loro semantica. La famiglia Lisp era strettamente legata alla semantica denotazionale. Senza entrare nei dettagli, questo tipo di semantica ha particolari difficoltà con qualcosa che siamo diventati "dichiarazioni", che non sono "espressioni". I significati del codice sono in genere pensati in termini di combinazioni di funzioni, mentre una "istruzione" che non può nemmeno essere descritta come una funzione (poiché non valuta nulla) è quindi difficile da gestire. Tuttavia, poiché Lisp consente effetti collaterali, a volte un programmatore vorrebbe usare un'espressione senza usare il suo valore in modo tale da non influenzare l'espressione che la segue. Ed è qui che progXentra in gioco la famiglia.

Nei linguaggi di tipo C questa funzione è talvolta nota come punto di sequenza (ad esempio ;e ,ad esempio). prognè essenziale per le lingue di tipo Lisp come per le lingue ;di tipo C. È una caratteristica fondamentale del linguaggio che non si può facilmente sostituire. Tuttavia, a differenza dei linguaggi in stile C, Lisp tende a costruire astrazioni sintattiche nascondendo completamente la sintassi del livello inferiore. E forse questo è il motivo per cui non vedete molto prognspesso questo uso, eppure è uno degli elementi costitutivi importanti, quando si tratta di costruire astrazioni linguistiche di livello superiore (sa macro).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.