Я видел progn
, как меня довольно часто используют, просматривая файлы конфигурации опытных пользователей Emacs. Я нашел это хорошее объяснениеprogn
, но что меня действительно интересует, так это какая польза от использования этой функции? Возьмем, к примеру, этот фрагмент (взят из конфигурации Саши Чуа ):
(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)))
Есть ли существенная разница между вышеуказанной конфигурацией и этой?
(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))
Я чувствую, что первый пример несколько чище, хотя у него больше синтаксиса, и моя интуиция заключается в том, что при использовании может быть какое-то повышение производительности progn
, но я не уверен. Спасибо за любые идеи!
use-package
обтеканиеprogn
форм: config, если оно отсутствует. Попробуйте: вы можете поставить точку в конце a(use-package ...)
и вызвать,M-x pp-macroexpand-last-sexp
чтобы увидеть, как раскрывается макрос. Вы увидите, что это идентично для этих двух примеров.progn
это необходимо: emacs.stackexchange.com/questions/39172/…Ответы:
progn
обычно используется при работе с макросами. Некоторые макросы (use-package
это макрос, который я последний раз проверял) принимают только 1 форму , где другие используют все оставшиеся формы .progn
используется в первом случае, чтобы превратить последовательность форм в одну форму.В ваших примерах используется первый
progn
и, следовательно, есть 1 форма после:config
. Во втором есть 3 формы . Еслиuse-package
макрос ожидает только 1 следующую форму:config
, он вызовет ошибку.Стоит отметить, что использование
progn
работает в обоих случаях, а его пропуск работает только в том случае, если макрос принимает несколько форм. В результате этого некоторые люди предпочитают просто всегда использоватьprogn
, потому что это всегда будет работать.источник
progn
», что означает, что они принимают любое количество секций в качестве отдельных аргументов и оценивают их последовательно. Другие этого не делают, и вместо этого ожидают / допускают только один аргумент, в котором вы, возможно, захотите оценить несколько сексов по порядку. Это все, чтоprogn
нужно: он позволяет вам предоставить один sexp, который при оценке вычисляет аргументы sexp поprogn
порядку. Сравните(if true (progn a b c))
с(when true a b c)
. В обоих случаяхa
,b
иc
оцениваются в последовательности.use-package
позволяет несколько форм в:config
и:init
.progn
сексп, который содержит несколько секпсов, которые оцениваются на предмет их побочных эффектов, прежде чем возвращать результат последнего из них. Это действительно не имеет ничего общего с макросами. Макросы "как пример" - это хорошо. Создавать впечатление, чтоprogn
существует для макросов, и что 99% его использования для макросов, вводит в заблуждение, ИМО.progn
Речь идет о сведении последовательности оценок в один пол (чтобы соответствовать заданному ожидаемому аргументу), и поэтому о побочных эффектах .progn
был представлен в Lisp 1.5 (см. Раздел « Возможности программы» ) в 1962 году, задолго до того, как в Lisp были добавлены макросы. Цель состоит в том, чтобы последовательно оценить выражения для их побочных эффектов. 2. Узнайте,progn
как Emacs сам знакомитprogn
программистов с Elisp. Смотритеzap-to-char
код для простого варианта использования.progn
это не имеет ничего общего с макросами. Его назначение, конечно, « передать несколько форм как одну форму » (ваши слова) - как функции, так и макросу или специальной форме, но также и « Eval BODY формы последовательно и возвращаемое значение последней » (строка документа) ). Теперь как всегда («эти дни», действительно!). Упорядоченная оценка важна только для побочных эффектов, очевидно. Данный вариант использования (макрос или нет) может или не может заботиться о порядке оценки, но это не имеет значения. И Emacs Lisp не является исключительным в этом отношении.Наиболее важная причина для progn описана в первой строке документации по progn (выделение добавлено):
Приложение:
Без progn последовательность не гарантируется, особенно если последующие выражения зависят от побочных эффектов или возвращаемых значений предыдущих выражений. progn принудительно выполняет последовательность выполнения так же, как текстовая последовательность. Помогает не путать исполнение с разбором. Это поведение восходит к основам структур управления LISP и функционального программирования. Вот выдержка (выделение выделено) из справочного руководства по lisp :
Есть ли progn повысить производительность?
Разбор производительности, нет. Исполнение исполнения, нет. В лучшем случае это может быть равно, но никогда не может волшебным образом повысить производительность.
Когда используется прог ?
источник
if
), но обычный порядок оценки (например, формы верхнего уровня, функциональные тела и т. Д.) Является текстовым. Конечно, в некоторой степени это неявноprogn
, но обычно это не то, что вы используетеprogn
в своем собственном коде.(elisp) Sequencing
который вы ссылаетесь, говорит сам за себя.Лучший способ понять, что
progn
есть, сравнивая это с семьей:prog1
иprog2
.n
Или1
или2
часть имени выступает за утверждение из списка, результат которого вас интересует. Другими словами,progn
возвращает результат последнего утверждения он содержит, в то время какprog1
будет возвращать первый, и аналогично дляprog2
.Сегодня эта функциональность кажется немного неловкой, поскольку мы учимся либо ожидать, что программа вернётся в последнем утверждении, либо явно указывать ей, что возвращать. Таким образом
prog1
иprog2
очень редко используются. Однако, если вы думаете об этом, это имеет смысл, и вот как:Различные языки программирования используют разные стратегии для описания своей семантики. Семейство Лисп раньше было тесно связано с денотационной семантикой. Не вдаваясь в подробности, этот вид семантики имеет особые трудности с тем, что мы стали называть «заявлениями», которые не являются «выражениями». Значения кода обычно рассматриваются в терминах комбинаций функций, в то время как с «оператором», который даже не может быть описан как функция (поскольку он ничего не оценивает), таким образом, трудно иметь дело. Однако, поскольку Lisp допускает побочные эффекты, иногда программисту хотелось бы использовать выражение, не используя его значение таким образом, чтобы оно не влияло на выражение, следующее за ним. И вот
progX
тут приходит семья.В C-подобных языках эта функция иногда известна как точка последовательности (т.е.
;
и,,
например).progn
столь же важен для языков, подобных Лисп, как и для языков,;
подобных С. Это фундаментальная особенность языка, которую нельзя легко заменить. Однако, в отличие от языков в стиле C, Lisp имеет тенденцию создавать синтаксические абстракции, полностью скрывая синтаксис нижнего уровня. И это, возможно, почему вы не видите,progn
использовали все это часто, но это один из важных строительных блоков, когда речь идет о построении языковых абстракций более высокого уровня (например, макросов).источник