Fexpr - Fexpr

Em linguagens de programação Lisp , um fexpr é uma função cujos operandos são passados ​​para ela sem serem avaliados. Quando um fexpr é chamado, apenas o corpo do fexpr é avaliado; nenhuma outra avaliação ocorre, exceto quando explicitamente iniciada pelo fexpr. Em contraste, quando uma função Lisp comum é chamada, os operandos são avaliados automaticamente e apenas os resultados dessas avaliações são fornecidos para a função; e quando uma macro Lisp (tradicional) é chamada, os operandos são passados ​​sem avaliação, mas qualquer resultado que a função macro retornar é avaliado automaticamente.

Origem do nome "fexpr"

No início do Lisp, o ambiente mapeia cada símbolo para uma lista de associação , em vez de diretamente para um valor. As chaves padrão para essas listas incluíam duas chaves usadas para armazenar um valor de dados, a serem consultadas quando o símbolo ocorresse como um argumento ( APVAL e APVAL1 ); e quatro teclas para armazenar uma função, a serem consultadas quando o símbolo ocorresse como operador. Das teclas de função, SUBR indicava uma função ordinária compilada, cujos operandos eram avaliados e passados ​​para ela; FSUBR indicou uma forma especial compilada, cujos operandos foram passados ​​sem avaliação; EXPR indicava uma função comum definida pelo usuário; e FEXPR indica uma forma especial definida pelo usuário. A única diferença entre um FEXPR e um EXPR era se os operandos eram avaliados automaticamente.

No uso original estrito, um FEXPR é, portanto, uma função definida pelo usuário cujos operandos são passados ​​sem avaliação. No entanto, em uso posterior, o termo fexpr pode descrever qualquer função de primeira classe cujos operandos são passados ​​sem avaliação, independentemente de a função ser primitiva ou definida pelo usuário.

Chave Lojas Definido por Função / formulário especial
APVAL valor de dados - -
APVAL1 valor de dados - -
SUBR função sistema função
FSUBR função sistema forma especial
EXPR função do utilizador função
FEXPR função do utilizador forma especial

Exemplo

Como uma ilustração simples de como o fexprs funciona, aqui está uma definição de fexpr escrita na linguagem de programação Kernel , que é semelhante ao Scheme . (Por convenção no Kernel, os nomes dos fexprs sempre começam com $ .)

($define! $f
   ($vau (x y z) e
      ($if (>=? (eval x e) 0)
           (eval y e)
           (eval z e))))

Essa definição fornece um fexpr chamado $ f , que leva três operandos. Quando o fexpr é chamado, um ambiente local é criado estendendo o ambiente estático onde o fexpr foi definido. Vinculações locais são então criadas: os símbolos x , y e z são vinculados aos três operandos da chamada ao fexpr e o símbolo e é vinculado ao ambiente dinâmico a partir do qual o fexpr está sendo chamado. O corpo do fexpr, ($ if  ... ) , é então avaliado neste ambiente local, e o resultado dessa avaliação torna-se o resultado da chamada ao fexpr. O efeito líquido é que o primeiro operando é avaliado no ambiente dinâmico e, dependendo se o resultado dessa avaliação for não negativo, o segundo ou o terceiro operando é avaliado e esse resultado retornado. O outro operando, o terceiro ou o segundo, não é avaliado.

Este exemplo tem escopo estático : o ambiente local é uma extensão do ambiente estático. Antes de cerca de 1980, as linguagens Lisp que suportavam fexprs tinham escopo principalmente dinâmico: o ambiente local era uma extensão do ambiente dinâmico, ao invés do ambiente estático. No entanto, às vezes ainda era necessário fornecer um nome local para o ambiente dinâmico, para evitar a captura dos nomes dos parâmetros locais.

Uso predominante e suspensão de uso

O suporte a Fexpr continuou no Lisp 1.5 , o último dialeto substancialmente padrão do Lisp antes de se fragmentar em vários idiomas. Na década de 1970, as duas linguagens Lisp dominantes - MacLisp e Interlisp - suportavam fexprs.

Na Conferência de 1980 sobre Lisp e Programação Funcional , Kent Pitman apresentou um artigo "Formas Especiais em Lisp", no qual ele discutiu as vantagens e desvantagens de macros e fexprs e, por fim, condenou os fexprs. Sua objeção central era que, em um dialeto Lisp que permite fexprs, a análise estática não pode determinar geralmente se um operador representa uma função comum ou um fexpr - portanto, a análise estática não pode determinar se os operandos serão avaliados ou não. Em particular, o compilador não pode dizer se uma subexpressão pode ser otimizada com segurança, uma vez que a subexpressão pode ser tratada como dados não avaliados em tempo de execução.

Os MACROs oferecem um mecanismo adequado para especificar definições de formulários especiais e ... os FEXPR 's não. ... É sugerido que, no projeto de dialetos Lisp futuros, uma consideração séria deve ser dada à proposição de que FEXPR 's devem ser omitidos da linguagem por completo.

Desde o declínio do MacLisp e do Interlisp, as duas linguagens Lisp que alcançaram o domínio em 1993 - Scheme e Common Lisp - não suportam fexprs. newLISP suporta fexprs, mas os chama de "macros". No Picolisp, todas as funções embutidas são fsubrs, enquanto as funções de nível Lisp são exprs, fexprs, lexprs ou uma mistura delas.

fexprs desde 1980

Começando com o 3-Lisp de Brian Smith em 1982, vários dialetos experimentais do Lisp foram desenvolvidos para explorar os limites da reflexão computacional . Para apoiar a reflexão, esses Lisps suportam procedimentos que podem reificar várias estruturas de dados relacionadas à chamada a eles - incluindo os operandos não avaliados da chamada, o que torna esses procedimentos fexprs. No final da década de 1990, os fexprs tornaram-se associados principalmente à reflexão computacional.

Alguns resultados teóricos sobre fexprs foram obtidos. Em 1993, John C. Mitchell usou Lisp com fexprs como um exemplo de linguagem de programação cujas expressões de origem não podem ser formalmente abstratas (porque a sintaxe concreta de uma expressão de origem pode sempre ser extraída por um contexto no qual é um operando para um fexpr ) Em 1998, Mitchell Wand mostrou que adicionar um dispositivo fexpr ao cálculo lambda - um dispositivo que suprime a reescrita de operandos - produz um sistema formal com uma teoria equacional trivial , tornando impossível fazer otimizações de origem a origem sem uma análise de todo o programa . Em 2007, John N. Shutt propôs uma extensão do cálculo lambda que modelaria fexprs sem suprimir a reescrita de operandos, evitando ostensivamente o resultado de Wand.

Veja também

As seguintes linguagens implementam fexprs ou equivalentes próximos:

Notas de rodapé

Referências

  • McCarthy, J .; Brayton, R .; Edwards, D .; Fox, P .; Hodes, L .; Luckham, D .; Maling, K .; Park, D .; Russell, S. (março de 1960), LISP I Programmers Manual (PDF) , Boston , Massachusetts : Artificial Intelligence Group, MIT Computation Center and Research Laboratory Acessado em 11 de maio de 2010.
  • John C. Mitchell, "On Abstraction and the Expressive Power of Programming Languages" , Science of Computer Programming 212 (1993), pp. 141-163. (Edição especial de artigos de Symp. Theor. Aspects of Computer Software, Sendai, Japão, 1991.) Acessado em 24 de janeiro de 2008.
  • Kent M. Pitman, "Special Forms in Lisp" , Proceedings of the 1980 ACM Conference on Lisp and Functional Programming, 1980, pp. 179-187. Acessado em 25 de janeiro de 2008.
  • Kent M. Pitman, The Revised MacLisp Manual (edição de sábado à noite), MIT Laboratory for Computer Science Technical Report 295, 21 de maio de 1983.
  • John N. Shutt, "vau-calculi and the theory of fexprs", palestra, New England Programming Languages ​​and Systems Symposium Series (NEPLS) , 18 de outubro de 2007. Resumo acessado em 27 de janeiro de 2008.
  • Guy L. Steele e Richard P. Gabriel, "The Evolution of Lisp", ACM SIGPLAN Avisos 28 no. 3 (março de 1993), pp. 231–270.
  • Mitchell Wand, "The Theory of Fexprs is Trivial" , Lisp and Symbolic Computation 10 no. 3 (maio de 1998), pp. 189–199. Acessado em 25 de janeiro de 2008.