Pergunta

Eu li muito que o LISP pode redefinir a sintaxe rapidamente, provavelmente com macros.Estou curioso para saber até onde isso realmente vai?Você pode redefinir tanto a estrutura da linguagem que ela se torna um compilador para outra linguagem?Por exemplo, você poderia mudar a natureza funcional do LISP para uma sintaxe e semântica mais orientadas a objetos, talvez digamos, tendo uma sintaxe mais próxima de algo como Ruby?

Principalmente, é possível se livrar do inferno dos parênteses usando macros?Aprendi (Emacs-)LISP o suficiente para personalizar o Emacs com meus próprios micro-recursos, mas estou muito curioso para saber até onde as macros podem ir na personalização da linguagem.

Foi útil?

Solução

Essa é uma pergunta muito boa.

Acho que tem nuances, mas definitivamente é responsável:

As macros não ficam presas em expressões s.Veja a macro LOOP para uma linguagem muito complexa escrita com palavras-chave (símbolos).Portanto, embora você possa iniciar e terminar o loop com parênteses, dentro dele há sua própria sintaxe.

Exemplo:

(loop for x from 0 below 100
      when (even x)
      collect x)

Dito isto, a maioria das macros simples usa apenas expressões s.E você ficaria "preso" a usá-los.

Mas as expressões S, como Sergio respondeu, começam a parecer certas.A sintaxe sai do caminho e você começa a codificar na árvore de sintaxe.

Quanto às macros de leitura, sim, você poderia escrever algo assim:

#R{
      ruby.code.goes.here
  }

Mas você precisaria escrever seu próprio analisador de sintaxe Ruby.

Você também pode imitar algumas das construções Ruby, como blocos, com macros que compilam para as construções Lisp existentes.

#B(some lisp (code goes here))

traduziria para

(lambda () (some lisp (code goes here)))

Ver esta página para saber como fazer isso.

Outras dicas

Sim, você pode redefinir a sintaxe para que o Lisp se torne um compilador.Você faz isso usando "Macros de leitura", que são diferentes das "Macros de compilador" normais nas quais você provavelmente está pensando.

Common Lisp tem o recurso integrado para definir uma nova sintaxe para o leitor e as macros do leitor processarem essa sintaxe.Esse processamento é feito em tempo de leitura (que vem antes do tempo de compilação ou avaliação).Para saber mais sobre como definir macros de leitura no Common Lisp, consulte Common Lisp Hyperspec - você vai querer ler CH.2, "Sintaxe" e CH.23, "Leitor".(Acredito que Scheme tenha a mesma facilidade, mas não estou tão familiarizado com isso - veja o Fontes do esquema para o Linguagem de programação Arc).

Como um exemplo simples, suponhamos que você queira que o Lisp use chaves em vez de parênteses.Isso requer algo como as seguintes definições do leitor:

;; { and } become list delimiters, along with ( and ).
(set-syntax-from-char #\{ #\( )
(defun lcurly-brace-reader (stream inchar) ; this was way too easy to do.
  (declare (ignore inchar))
  (read-delimited-list #\} stream t))
(set-macro-character #\{ #'lcurly-brace-reader)

(set-macro-character #\} (get-macro-character #\) ))
(set-syntax-from-char #\} #\) )

;; un-lisp -- make parens meaningless
(set-syntax-from-char #\) #\] ) ; ( and ) become normal braces
(set-syntax-from-char #\( #\[ )

Você está dizendo ao Lisp que { é como a ( e que } é como a ).Então você cria uma função (lcurly-brace-reader) que o leitor chamará sempre que vir um {, e você usa set-macro-character para atribuir essa função ao {.Então você diz ao Lisp que ( e ) são como [ e ] (isto é, sem sintaxe significativa).

Outras coisas que você pode fazer incluem, por exemplo, criando uma nova sintaxe de string ou usando [e] para incluir a notação fixa e processá-la em expressões S.

Você também pode ir muito além disso, redefinindo toda a sintaxe com seus próprios caracteres macro que irão desencadear ações no leitor, para que o céu seja realmente o limite.Esta é apenas uma das razões pelas quais Paulo Graham e outros continuo dizendo que Lisp é uma boa linguagem para escrever um compilador.

Eu não sou um especialista em Lisp, nem sou um programador Lisp, mas depois de experimentar um pouco com a linguagem cheguei à conclusão que depois de um tempo os parênteses começam a ficar 'invisíveis' e você começa a ver o código como você quer que seja.Você começa a prestar mais atenção às construções sintáticas que cria por meio de s-exprs e macros, e menos à forma lexical do texto das listas e parênteses.

Isto é especialmente verdadeiro se você aproveitar um bom editor que ajuda com o recuo e a coloração da sintaxe (tente definir o parêntese para uma cor muito semelhante ao fundo).

Talvez você não consiga substituir completamente o idioma e obter a sintaxe 'Ruby', mas não precisa disso.Graças à flexibilidade da linguagem, você pode acabar tendo um dialeto que parece seguir o 'estilo de programação Ruby', se quiser, seja lá o que isso signifique para você.

Eu sei que esta é apenas uma observação empírica, mas acho que tive um daqueles momentos de iluminação do Lisp quando percebi isso.

Repetidas vezes, os recém -chegados a Lisp querem "se livrar de todos os parênteses". Dura algumas semanas.Nenhum projeto para construir uma sintaxe de programação de uso geral grave sobre o analisador de expressão s usual de S de sempre chega a qualquer lugar, porque os programadores invariavelmente acabam preferindo o que você percebe atualmente como "parênteses infernal". Demora um pouco para se acostumar, mas não muito!Depois que você se acostumar e puder realmente apreciar a plasticidade da sintaxe padrão, voltar às linguagens onde só há uma maneira de expressar qualquer construção de programação específica é realmente irritante.

Dito isto, Lisp é um excelente substrato para a construção de linguagens específicas de domínio.Tão bom quanto, senão melhor, que XML.

Boa sorte!

A melhor explicação das macros Lisp que já vi está em

https://www.youtube.com/watch?v=4NO83wZVT0A

começando por volta dos 55 minutos.Este é o vídeo de uma palestra proferida por Peter Seibel, autor de "Practical Common Lisp", que é o melhor livro didático sobre Lisp que existe.

A motivação para macros Lisp geralmente é difícil de explicar, porque elas realmente se destacam em situações que são muito longas para serem apresentadas em um tutorial simples.Peter apresenta um ótimo exemplo;você pode compreendê-lo completamente e faz um uso bom e adequado das macros Lisp.

Você perguntou:"você poderia mudar a natureza funcional do LISP para uma sintaxe e semântica mais orientada a objetos".A resposta é sim.Na verdade, o Lisp originalmente não tinha nenhuma programação orientada a objetos, o que não é surpreendente, já que o Lisp já existe muito antes da programação orientada a objetos!Mas quando aprendemos sobre OOP pela primeira vez em 1978, conseguimos adicioná-lo facilmente ao Lisp, usando, entre outras coisas, macros.Eventualmente, o Common Lisp Object System (CLOS) foi desenvolvido, um sistema de programação orientado a objetos muito poderoso que se encaixa perfeitamente no Lisp.A coisa toda pode ser carregada como uma extensão – nada está embutido!Tudo é feito com macros.

Lisp possui um recurso totalmente diferente, chamado "leitor de macros", que pode ser usado para estender a sintaxe de superfície da linguagem.Usando macros de leitura, você pode criar sublinguagens com sintaxe semelhante a C ou Ruby.Eles transformam o texto em Lisp, internamente.Eles não são amplamente utilizados pela maioria dos programadores Lisp reais, principalmente porque é difícil estender o ambiente de desenvolvimento interativo para compreender a nova sintaxe.Por exemplo, os comandos de indentação do Emacs seriam confundidos por uma nova sintaxe.Porém, se você for enérgico, o Emacs também é extensível e você poderá ensiná-lo sobre sua nova sintaxe lexical.

Macros regulares operam em listas de objetos.Mais comumente, esses objetos são outras listas (formando assim árvores) e símbolos, mas podem ser outros objetos, como strings, hashtables, objetos definidos pelo usuário, etc.Essas estruturas são chamadas s-exps.

Portanto, quando você carrega um arquivo fonte, seu compilador Lisp irá analisar o texto e produzir s-exps.Macros operam sobre eles.Isso funciona muito bem e é uma maneira maravilhosa de estender a linguagem dentro do espírito do s-exps.

Além disso, o processo de análise mencionado acima pode ser estendido por meio de "macros de leitura" que permitem personalizar a maneira como seu compilador transforma texto em s-exps.Sugiro, entretanto, que você adote a sintaxe do Lisp em vez de transformá-la em outra coisa.

Você parece um pouco confuso ao mencionar a "natureza funcional" do Lisp e a "sintaxe orientada a objetos" do Ruby.Não tenho certeza do que deveria ser "sintaxe orientada a objetos", mas Lisp é uma linguagem multiparadigma e suporta programação orientada a objetos extremamente bem.

Aliás, quando digo Lisp, quero dizer Lisp comum.

Eu sugiro que você deixe seus preconceitos de lado e dê ao Lisp uma chance honesta.

Inferno entre parênteses?Não vejo mais parênteses em:

(function toto)

do que em:

function(toto);

E em

(if tata (toto)
  (titi)
  (tutu))

não mais do que em:

if (tata)
  toto();
else
{
  titi();
  tutu();
}

Eu vejo menos colchetes e ';' no entanto.

O que você está perguntando é como se tornar um especialista em chocolate para poder remover toda aquela coisa marrom infernal do seu bolo de chocolate favorito.

Sim, você pode alterar fundamentalmente a sintaxe e até escapar do "inferno dos parênteses".Para isso você precisará definir uma nova sintaxe de leitor.Observe as macros do leitor.

Eu suspeito, no entanto, que para atingir o nível de conhecimento em Lisp para programar tais macros, você precisará mergulhar na linguagem a tal ponto que não considerará mais os parênteses como "inferno".Ou sejaquando você souber como evitá-los, você terá passado a aceitá-los como uma coisa boa.

Se você quiser que o lisp se pareça com Ruby, use Ruby.

É possível usar Ruby (e Python) de uma maneira muito semelhante ao lisp, que é uma das principais razões pelas quais eles ganharam aceitação tão rapidamente.

veja este exemplo de como as macros do leitor podem estender o leitor lisp com tarefas complexas, como modelos XML:

http://common-lisp.net/project/cl-quasi-quote/present-class.html

esse biblioteca do usuário compila as partes estáticas do XML em matrizes de bytes literais codificadas em UTF-8 em tempo de compilação que estão prontas para serem sequenciadas por gravação no fluxo da rede.e são utilizáveis ​​em macros lisp normais, são ortogonais ...o posicionamento do caractere vírgula influencia quais partes são constantes e quais devem ser avaliadas em tempo de execução.

mais detalhes disponíveis em: http://common-lisp.net/project/cl-quasi-quote/

outro projeto que para extensões de sintaxe Common Lisp: http://common-lisp.net/project/cl-syntax-sugar/

@sparkes

Às vezes, LISP é a escolha de linguagem mais clara, ou seja, extensões Emacs.Tenho certeza de que poderia usar Ruby para estender o Emacs se quisesse, mas o Emacs foi projetado para ser estendido com LISP, então parece fazer sentido usá-lo nessa situação.

É uma pergunta complicada.Como o lisp já está estruturalmente tão próximo de uma árvore de análise, a diferença entre um grande número de macros e a implementação de sua própria minilinguagem em um gerador de análise não é muito clara.Mas, exceto pelo parêntese de abertura e fechamento, você pode facilmente acabar com algo que não se parece em nada com lisp.

Um dos usos de macros que me surpreendeu foi a verificação em tempo de compilação de solicitações SQL em relação ao banco de dados.

Depois que você perceber que tem a linguagem completa em tempo de compilação, isso abrirá novas perspectivas interessantes.O que também significa que você pode dar um tiro no próprio pé de novas maneiras interessantes (como tornar a compilação não reproduzível, o que pode facilmente se transformar em um pesadelo de depuração).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top