Quando / por que devo usar o progn?


19

Eu tenho visto prognbastante uso enquanto navego nos arquivos de configuração de usuários experientes do Emacs. Encontrei essa boa explicação deprogn , mas o que realmente me interessa é: qual é o benefício de usar essa função? Tomemos, por exemplo, este trecho (retirado da configuração do 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)))

Existe alguma diferença importante entre a configuração acima e essa?

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

Eu sinto que o primeiro exemplo é de alguma forma mais limpo, embora tenha mais sintaxe, e minha intuição é que pode haver algum tipo de aumento de desempenho no uso progn, mas não tenho certeza. Obrigado por qualquer insight!


7
Nesse caso em particular, não há diferença: use-packageenvolverá os prognformulários: config se ele estiver ausente. Experimente: você pode colocar um ponto no final de um (use-package ...)e ligar M-x pp-macroexpand-last-sexppara ver como a macro é expandida. Você verá que é idêntico para esses dois exemplos.
glucas

Um exemplo onde progné necessário: emacs.stackexchange.com/questions/39172/…
npostavs

Respostas:


11

progné normalmente usado ao lidar com macros. Algumas macros ( use-packageuma macro, verifiquei pela última vez) aceitam apenas 1 formulário , enquanto outras consomem todos os formulários restantes .

progn é usado no primeiro caso para transformar uma sequência de formulários em um único formulário.

Nos seus exemplos, o primeiro usa progne, portanto, existe 1 formulário depois :config. No segundo, existem três formas . Se a use-packagemacro espera apenas 1 formulário a seguir :config, isso causará um erro.

Vale ressaltar que o uso de prognobras nos dois casos, enquanto a omissão só funciona se a macro aceitar vários formulários. Como resultado disso, algumas pessoas preferem simplesmente usar sempre progn, porque sempre funcionará.


15
Realmente não tem nada a ver com macros. Algumas funções e macros têm o chamado "implícito progn", o que significa que aceitam qualquer número de sexps como argumentos separados e os avaliam em sequência. Outros não, e esperam / permitem apenas um único argumento em que você pode avaliar vários sexps em sequência. Isso é tudo progn: permite fornecer um único sexp que, quando avaliado, avalia os argumentos do sexp prognem sequência. Compare (if true (progn a b c))com (when true a b c). Em ambos os casos, a, b, e csão avaliadas em sequência.
Tirou


4
Não concordo que 99% dos casos de uso sejam para macros etc. Qualquer função ou macro pode receber um prognsexp que contenha vários sexps avaliados por seus efeitos colaterais, antes de retornar o resultado do último deles. Realmente não tem nada a ver com macros. Macros "como exemplo" está bem. Dar a impressão de que prognexiste para macros e que 99% de seu uso é para macros é enganoso, IMO. progntrata-se de colocar uma sequência de avaliações em um único sexp (para ajustar-se a um dado argumento esperado) e, portanto, trata-se de efeitos colaterais .
Tirou

5
1. prognfoi introduzido no Lisp 1.5 (consulte a seção O Recurso do Programa ), em 1962, muito antes de as macros serem adicionadas ao Lisp. O objetivo é avaliar sequencialmente expressões para seus efeitos colaterais. 2. Veja progncomo o próprio Emacs apresenta prognaos programadores do Elisp. Veja o zap-to-charcódigo para um caso de uso simples.
Tirou

2
Podemos concordar em discordar. O que quero dizer é que nãoprogn tem nada a ver com macros. É claro que seu objetivo é " passar várias formas como uma única forma " (suas palavras) - seja para uma função ou macro ou uma forma especial, mas também para " Eval BODY forms sequencialmente e retornar valor do último " (doc string ) Agora como sempre ("nos dias de hoje", de fato!). Uma avaliação ordenada é importante apenas para efeitos colaterais, obviamente. Um determinado caso de uso (macro ou não) pode ou não se importar com a ordem de avaliação, mas isso é irrelevante. E o Emacs Lisp não é excepcional de forma alguma a esse respeito.
Tirou

10

O motivo mais importante para o progn é descrito na primeira linha da documentação do progn (ênfase adicionada):

progn é uma forma especial que faz com que cada um de seus argumentos seja avaliado em sequência e, em seguida, retorna o valor do último.

Termo aditivo:

Sem progn , a sequência não é garantida, especialmente se expressões subsequentes dependem dos efeitos colaterais ou retornam valores das expressões anteriores. progn força a sequência de execução da mesma forma que a sequência textual. Ajuda a não confundir execução com análise. Esse comportamento remonta aos fundamentos das estruturas de controle lisp e da programação funcional. Aqui está um trecho (ênfase adicionada) do manual de referência lisp :

As estruturas de controle internas são formas especiais, pois seus subformulários não são necessariamente avaliados ou avaliados seqüencialmente .

O progn melhora o desempenho?

Análise de desempenho, não. Desempenho de execução, não. Na melhor das hipóteses, pode ser igual, mas nunca aumentar magicamente o desempenho.

Quando o progn é usado ?

... na maioria das vezes dentro de uma proteção contra desenrolar e, ou , ou na parte então de um if .


Não sei por que isso é tão importante. O Emacs sempre avalia sequencialmente.
Lunardorn 03/12/2015

2
@lunaryorn veja a resposta atualizada.
Emacs User

Não tenho certeza se entendi sua edição. Naturalmente, existem formulários especiais com uma ordem de avaliação diferente (por exemplo if), mas a ordem de avaliação normal (por exemplo, formulários de nível superior, corpos funcionais etc.) é textual. Claro, até certo ponto isso é implícito progn, mas geralmente não é progn para isso que você usa em seu próprio código.
lunaryorn

Acho que o nó manual do Elisp ao (elisp) Sequencingqual você vincula diz tudo.
Basil

10

Uma maneira melhor de entender o que progné é comparando-o com a família: prog1e prog2. A nou 1ou 2parte do nome significa a afirmação da lista cujo resultado você está interessado. Em outras palavras, prognirá devolver o resultado da última declaração que contém, enquanto que prog1irá retornar o primeiro, e semelhante para prog2.

Hoje, essa funcionalidade parece um pouco estranha, pois aprendemos a esperar que o programa retorne na última instrução ou a instruí-lo explicitamente sobre o que retornar. Assim prog1e prog2raramente são usados. No entanto, se você pensar sobre isso, faz sentido, e aqui está como:

Diferentes linguagens de programação usam estratégias diferentes para descrever sua semântica. A família Lisp costumava estar intimamente ligada à semântica denotacional. Sem entrar em muitos detalhes, esse tipo de semântica tem uma dificuldade particular com algo que passamos a conhecer como "declarações", que não são "expressões". Os significados do código são tipicamente pensados ​​em termos de combinações de funções, enquanto uma "declaração" que nem sequer pode ser descrita como uma função (já que não avalia nada) é, portanto, difícil de lidar. No entanto, como o Lisp permite efeitos colaterais, algumas vezes um programador gostaria de usar uma expressão sem usar seu valor de uma maneira que não afete a expressão que a segue. E é aí que a progXfamília entra.

Em idiomas do tipo C, esse recurso às vezes é conhecido como ponto de sequência ( por exemplo, ;e ,por exemplo). progné tão essencial para idiomas do tipo Lisp quanto ;para idiomas do tipo C. É uma característica fundamental do idioma que não se pode substituir facilmente. No entanto, diferentemente das linguagens de estilo C, o Lisp tende a criar abstrações sintáticas ao ocultar completamente a sintaxe do nível inferior. E talvez por isso você não seja prognusado com tanta frequência, ainda assim, é um dos blocos de construção importantes quando se trata de criar abstrações de linguagem de nível superior (em macros).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.