J'ai vu progn
beaucoup utilisé lorsque je parcourais les fichiers de configuration d'utilisateurs expérimentés d'Emacs. J'ai trouvé cette belle explicationprogn
, mais ce qui m'intéresse vraiment, c'est quel est l'avantage d'utiliser cette fonction? Prenons par exemple cet extrait (extrait de la configuration 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)))
Y a-t-il une différence majeure entre la configuration ci-dessus et celle-ci?
(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))
J'ai l'impression que le premier exemple est en quelque sorte plus propre, même s'il a plus de syntaxe, et mon intuition est qu'il pourrait y avoir une sorte d'amélioration des performances progn
, mais je ne suis pas sûr. Merci pour tout aperçu!
use-package
enroulera unprogn
autour de vos formulaires: config s'il est manquant. Essayez-le: vous pouvez mettre un point à la fin d'un(use-package ...)
et appelerM-x pp-macroexpand-last-sexp
pour voir comment la macro est développée. Vous verrez qu'il est identique pour ces deux exemples.progn
est nécessaire: emacs.stackexchange.com/questions/39172/…Réponses:
progn
est généralement utilisé pour les macros. Certaines macros (use-package
c'est une macro, la dernière que j'ai vérifiée) n'acceptent qu'un seul formulaire , tandis que d'autres consomment tous les formulaires restants .progn
est utilisé dans le premier cas pour transformer une séquence de formulaires en un seul formulaire.Dans vos exemples, le premier utilise
progn
et donc il y a 1 formulaire après:config
. Dans le second, il existe 3 formes . Si lause-package
macro n'attend qu'un formulaire suivant:config
, cela provoquera une erreur.Il convient de noter que l'utilisation
progn
fonctionne dans les deux cas, tout en l'omettant ne fonctionne que si la macro accepte plusieurs formulaires. En conséquence, certaines personnes préfèrent simplement toujours utiliserprogn
, car cela fonctionnera toujours.la source
progn
", ce qui signifie qu'elles acceptent n'importe quel nombre de sexps comme arguments séparés et les évaluent en séquence. D'autres ne le font pas et s'attendent à la place / n'autorisent qu'un seul argument où vous voudrez peut-être évaluer plusieurs sexps en séquence. C'est toutprogn
: il vous permet de fournir un seul sexp qui, une fois évalué, évalue les arguments de sexpprogn
en séquence. Comparez(if true (progn a b c))
avec(when true a b c)
. Dans les deux cas,a
,b
etc
sont évalués dans l' ordre.use-package
autorise plusieurs formes dans:config
et:init
.progn
sexp contenant plusieurs sexps évalués pour leurs effets secondaires, avant de renvoyer le résultat du dernier de ceux-ci. Cela n'a vraiment rien à voir avec les macros. Les macros "à titre d'exemple" sont très bien. Donner l'impression qu'ilprogn
existe pour les macros, et que 99% de son utilisation est pour les macros, est trompeur, OMI.progn
il s'agit de pelleter une séquence d'évaluations en un seul sexe (pour s'adapter à un argument attendu donné), et il s'agit donc d' effets secondaires .progn
été introduit dans Lisp 1.5 (voir la section La fonction du programme ), en 1962, bien avant l'ajout de macros à Lisp. Le but est d'évaluer séquentiellement les expressions pour leurs effets secondaires. 2. Découvrezprogn
comment Emacs se présenteprogn
aux programmeurs Elisp. Voir lezap-to-char
code pour un cas d'utilisation simple.progn
n'a rien à voir avec les macros. Son but est bien sûr de " passer plusieurs formulaires comme un seul formulaire " (vos mots) - que ce soit vers une fonction ou une macro ou un formulaire spécial, mais aussi vers " Eval BODY forms séquentiellement et renvoyer la valeur du dernier " (doc string ). Maintenant comme toujours ("ces jours-ci", en effet!). Une évaluation ordonnée n'est importante que pour les effets secondaires, évidemment. Un cas d'utilisation donné (macro ou non) peut ou non se soucier de l'ordre d'évaluation, mais cela n'est pas pertinent. Et Emacs Lisp n'est absolument pas exceptionnel à cet égard.La raison la plus importante pour progn est décrite dans la première ligne de la documentation progn (accent ajouté):
Addenda:
Sans progn , la séquence n'est pas garantie, surtout si les expressions suivantes dépendent des effets secondaires ou des valeurs de retour des expressions précédentes. progn applique la séquence d'exécution de la même manière que la séquence textuelle. Aide à ne pas confondre l'exécution avec l'analyse. Ce comportement remonte aux principes fondamentaux des structures de contrôle lisp et de la programmation fonctionnelle. Voici un extrait (soulignement ajouté) du manuel de référence lisp :
Est- ce que progn augmente les performances?
Analyse des performances, non. Performance d'exécution, non. Au mieux, il peut égaler, mais jamais augmenter les performances comme par magie.
Quand est-ce que progn est utilisé ?
la source
if
), mais l'ordre d'évaluation normal (par exemple, les formulaires de niveau supérieur, les organes de fonction, etc.) est textuel. Bien sûr, dans une certaine mesure, c'est impliciteprogn
, mais ce n'est généralement pas ce que vous utilisezprogn
dans votre propre code.(elisp) Sequencing
que vous liez en dit long.Une meilleure façon de comprendre ce qui
progn
est est de le comparer à la famille:prog1
etprog2
. Len
ou1
ou une2
partie du nom représente l'instruction de la liste dont le résultat vous intéresse. En d'autres termes,progn
renvoie le résultat de la dernière instruction qu'il contient, tandis queprog1
renvoie la première, et similaire pourprog2
.Aujourd'hui, cette fonctionnalité semble un peu gênante car nous apprenons à nous attendre à ce que le programme retourne dans la dernière instruction, ou à lui indiquer explicitement ce qu'il doit retourner. Ainsi
prog1
etprog2
sont très rarement utilisés. Cependant, si vous y réfléchissez, cela a du sens, et voici comment:Différents langages de programmation utilisent différentes stratégies pour décrire leur sémantique. La famille Lisp était étroitement liée à la sémantique dénotationnelle. Sans entrer dans les détails, ce type de sémantique a une difficulté particulière avec quelque chose que nous avons appris à connaître sous le nom d '"énoncés", qui ne sont pas des "expressions". Les significations du code sont généralement pensées en termes de combinaisons de fonctions, tandis qu'une «instruction» qui ne peut même pas être décrite comme une fonction (car elle n'évalue rien) est donc difficile à gérer. Cependant, puisque Lisp autorise les effets secondaires, parfois un programmeur voudrait utiliser une expression sans utiliser sa valeur de manière à ce qu'elle n'affecte pas l'expression qui la suit. Et c'est là que la
progX
famille entre en jeu.Dans les langages de type C, cette fonction est parfois appelée point de séquence (c'est
;
-à- dire et,
par exemple).progn
est aussi essentiel pour les langages de type Lisp que pour les langages de type;
C. C'est une caractéristique fondamentale de la langue que l'on ne peut pas facilement remplacer. Cependant, contrairement aux langages de style C, Lisp a tendance à construire des abstractions syntaxiques en masquant complètement la syntaxe du niveau inférieur. Et c'est peut-être la raison pour laquelle vous ne le voyez pasprogn
souvent, mais c'est l'un des éléments constitutifs importants, lorsqu'il s'agit de construire des abstractions de langage de niveau supérieur (macros sa).la source