Wann / warum sollte ich progn verwenden?


19

Beim prognDurchsuchen der Konfigurationsdateien erfahrener Emacs-Benutzer wurde ich häufig verwendet. Ich fand diese nette Erklärung vonprogn , aber was mich wirklich interessiert ist, was ist der Vorteil der Verwendung dieser Funktion? Nehmen Sie zum Beispiel diesen Ausschnitt (entnommen aus Sacha Chuas Konfiguration ):

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

Gibt es einen großen Unterschied zwischen der obigen Konfiguration und dieser?

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

Ich denke, das erste Beispiel ist irgendwie sauberer, obwohl es mehr Syntax hat, und meine Intuition ist, dass es eine Art Leistungssteigerung durch die Verwendung geben könnte progn, aber ich bin nicht sicher. Vielen Dank für eventuelle Einblicke!


7
In diesem speziellen Fall gibt es keinen Unterschied: use-packageWird prognIhre: config-Formulare umschließen, wenn sie fehlen. Probieren Sie es aus: Sie können einen Punkt am Ende von a setzen (use-package ...)und aufrufen, um M-x pp-macroexpand-last-sexpzu sehen, wie das Makro erweitert wird. Sie werden sehen, dass es für diese beiden Beispiele identisch ist.
Glucas

Ein Beispiel, wo prognes gebraucht wird: emacs.stackexchange.com/questions/39172/…
npostavs

Antworten:


11

prognwird normalerweise beim Umgang mit Makros verwendet. Einige Makros ( use-packageein Makro, das ich zuletzt überprüft habe) akzeptieren nur ein Formular , während andere alle verbleibenden Formulare verwenden .

progn wird im ersteren Fall verwendet, um eine Folge von Formularen in ein einziges Formular umzuwandeln.

In Ihren Beispielen wird das erste verwendet prognund daher gibt es 1 Formular danach :config. Im zweiten gibt es 3 Formen . Wenn das use-packageMakro nur 1 folgende Form erwartet :config, verursacht es einen Fehler.

Es ist erwähnenswert, dass die Verwendung prognin beiden Fällen funktioniert, während das Weglassen nur funktioniert, wenn das Makro mehrere Formen akzeptiert. Infolgedessen bevorzugen einige Leute einfach immer zu verwenden progn, weil es immer funktionieren wird.


15
Es hat wirklich nichts mit Makros zu tun. Einige Funktionen und Makros haben ein sogenanntes "implizites progn", dh sie akzeptieren eine beliebige Anzahl von Sexps als separate Argumente und werten sie nacheinander aus. Andere tun dies nicht und erwarten / erlauben stattdessen nur ein einziges Argument, bei dem Sie mehrere Sexps nacheinander bewerten möchten. Das ist alles progn: Sie können ein einzelnes sexp bereitstellen, das bei der Auswertung die sexp-Argumente nacheinander auswertet progn. Vergleichen Sie (if true (progn a b c))mit (when true a b c). In beiden Fällen werden a, bund der cReihe nach ausgewertet.
Drew


4
Ich bin nicht einverstanden, dass 99% der Anwendungsfälle für Makros usw. bestimmt sind. Jeder Funktion oder Makro kann ein prognSexp übergeben werden, der mehrere Sexps enthält, die auf ihre Nebenwirkungen hin untersucht werden, bevor das Ergebnis des letzten davon zurückgegeben wird. Es hat wirklich nichts mit Makros zu tun. Makros "als Beispiel" sind in Ordnung. Es prognist irreführend, den Eindruck zu erwecken, dass Makros existieren und zu 99% für Makros verwendet werden. prognEs geht darum, eine Sequenz von Bewertungen in ein einziges Geschlecht zu schaufeln (um zu einem gegebenen erwarteten Argument zu passen), und es geht daher um Nebenwirkungen .
Drew

5
1. prognwurde 1962 in Lisp 1.5 eingeführt (siehe Abschnitt Das Programmfeature ), lange bevor Makros zu Lisp hinzugefügt wurden. Der Zweck besteht darin, Ausdrücke nacheinander auf ihre Nebenwirkungen zu untersuchen. 2. Siehe progn, wie Emacs selbst führt prognzu Elisp Programmierer. Siehe den zap-to-charCode für einen einfachen Anwendungsfall.
Drew

2
Wir können zustimmen, nicht zuzustimmen. Mein Punkt ist, dass progndas überhaupt nichts mit Makros zu tun hat. Ihr Zweck ist es natürlich, " mehrere Formulare als ein einziges Formular zu übergeben " (Ihre Wörter) - ob an eine Funktion oder ein Makro oder ein spezielles Formular, aber auch an " BODY-Formulare nacheinander auswerten und den Wert des letzten zurückgeben " (doc string) ). Jetzt wie immer ("in diesen Tagen" tatsächlich!). Eine geordnete Bewertung ist natürlich nur für Nebenwirkungen wichtig. Ein gegebener Anwendungsfall (Makro oder nicht) kümmert sich möglicherweise nicht um die Auswertungsreihenfolge, aber das ist irrelevant. Und Emacs Lisp ist in dieser Hinsicht in keiner Weise außergewöhnlich.
Drew

10

Der wichtigste Grund für die Prognose wird in der ersten Zeile der Prognosedokumentation beschrieben (Hervorhebung hinzugefügt):

progn ist eine spezielle Form, bei der jedes Argument der Reihe nach ausgewertet wird und anschließend der Wert des letzten zurückgegeben wird.

Nachtrag:

Ohne Prognose kann die Reihenfolge nicht garantiert werden, insbesondere wenn nachfolgende Ausdrücke von den Nebenwirkungen oder Rückgabewerten der vorherigen Ausdrücke abhängen. progn erzwingt die Ausführungsreihenfolge genauso wie die Textreihenfolge . Hilft, die Ausführung nicht mit dem Parsen zu verwechseln. Dieses Verhalten geht auf die Grundlagen von Lisp-Kontrollstrukturen und funktionaler Programmierung zurück. Hier ist ein Auszug (Hervorhebung hinzugefügt) aus dem Lisp-Referenzhandbuch :

Die eingebauten Kontrollstrukturen sind spezielle Formulare, da ihre Unterformulare nicht unbedingt oder nicht nacheinander ausgewertet werden .

Hat progn Leistung zu steigern?

Parsing-Leistung, nein. Ausführungsleistung, nein. Bestenfalls kann es gleich sein, aber niemals die Leistung auf magische Weise steigern.

Wann wird progn verwendet ?

... am häufigsten in einem Unwind-Protect und, oder , oder im damaligen Teil eines If .


Ich bin mir nicht sicher, warum das so wichtig ist. Emacs wertet immer nacheinander aus.
Lunaryorn

2
@ Lunaryorn finden Sie in der aktualisierten Antwort.
Emacs User

Ich bin mir nicht sicher, ob ich deine Bearbeitung verstehe. Natürlich gibt es spezielle Formulare mit einer anderen Bewertungsreihenfolge (z. B. if), aber die normale Bewertungsreihenfolge (z. B. Formulare der obersten Ebene, Funktionskörper usw.) ist textuell. Sicher, bis zu einem gewissen Grad ist das implizit progn, aber normalerweise verwenden Sie das nicht progn für Ihren eigenen Code.
Lunaryorn

Ich denke, der Elisp-Handbuchknoten, (elisp) Sequencingden Sie verknüpfen, sagt schon alles.
Basil

10

Ein besserer Weg, um zu verstehen, was prognist, besteht darin, es mit der Familie zu vergleichen: prog1und prog2. Das noder 1oder ein 2Teil des Namens steht für die Anweisung aus der Liste, deren Ergebnis Sie interessiert. Mit anderen Worten, progngibt das Ergebnis der letzten Anweisung zurück, während prog1die erste und ähnliche zurückgegeben wird prog2.

Heutzutage scheint diese Funktionalität etwas umständlich zu sein, da wir lernen, entweder zu erwarten, dass das Programm in der letzten Anweisung zurückkehrt, oder es explizit anzuweisen, was zurückgegeben werden soll. Daher prog1und prog2werden sehr selten verwendet. Wenn Sie jedoch darüber nachdenken, ist es sinnvoll, und hier ist, wie:

Verschiedene Programmiersprachen verwenden unterschiedliche Strategien, um ihre Semantik zu beschreiben. Die Familie Lisp war eng mit der Denotationssemantik verbunden. Ohne ins Detail zu gehen, hat diese Art von Semantik besondere Schwierigkeiten mit etwas, das wir als "Aussagen" kennengelernt haben, die keine "Ausdrücke" sind. Codebedeutungen werden typischerweise in Form von Funktionskombinationen gedacht, während eine "Anweisung", die nicht einmal als Funktion beschrieben werden kann (da sie nichts wertet), daher schwierig zu behandeln ist. Da Lisp jedoch Nebenwirkungen zulässt, möchte ein Programmierer manchmal einen Ausdruck verwenden, ohne seinen Wert so zu verwenden, dass er den darauf folgenden Ausdruck nicht beeinflusst. Und hier kommt die progXFamilie ins Spiel.

In C-ähnlichen Sprachen ist diese Funktion manchmal als Sequenzpunkt (dh ;und ,zum Beispiel). prognist für Lisp-ähnliche Sprachen genauso wichtig wie ;für C-ähnliche Sprachen. Es ist ein grundlegendes Merkmal der Sprache, das man nicht einfach ersetzen kann. Im Gegensatz zu C-Sprachen tendiert Lisp jedoch dazu, syntaktische Abstraktionen zu erstellen, indem die Syntax der unteren Ebene vollständig ausgeblendet wird. Und das ist vielleicht der Grund, warum man es nicht so prognoft benutzt sieht , aber es ist einer der wichtigen Bausteine, wenn es darum geht, übergeordnete Sprachabstraktionen (sa-Makros) zu erstellen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.