Lisp é um negócio muito doido. Considere o seguinte trecho de código:
(+ 2 3)
Essa é uma expressão que, quando avaliada, produz a soma de 2 e 3. Mas mais que isso, essa expressão é uma lista de três elementos: +, 2 e 3.
Esse é o segredo por trás dos quilos de parênteses das linguagens da família Lisp: enquanto em uma linguagem convencional escrevemos os programas em uma sintaxe especial (e.g., 2+3), que é convertida em uma árvore sintática durante a compilação ou interpretação, em Lisp escrevemos a árvore sintática diretamente, usando uma notação uniforme de listas aninhadas. Quando escrevemos 2*3+4*5 em uma linguagem convencional, o compilador/interpretador produz internamente uma estrutura de dados muito similar ao (+ (* 2 3) (* 4 5)) do Lisp.
Aí você se pergunta: por que escrever a árvore sintática diretamente, se o compilador pode fazer isso por mim? Uma resposta é que escrever a árvore sintática diretamente torna a vida de quem escreve o compilador mais fácil. A segunda questão é: o que é que eu tenho a ver com isso? A reposta é que, em Lisp, quem escreve o compilador é VOCÊ!!
A principal característica que distingue os Lisps da maior parte das linguagens de programação é a extensibilidade: você pode adicionar novas construções sintáticas à linguagem, sem ter que alterar o compilador, através do mecanismo de macros. Macros em Lisp não são como as macros localizar-e-substituir do C. As macros do Lisp são funções, que recebem como entrada um trecho de código, e retornam como saída outro trecho de código. Definindo macros, você pode estender a linguagem como bem entender. E como a estrutura do código é uniformemente expressa por listas, você não precisa se preocupar em parsear texto; a macro já recebe a lista parseada que representa o código como entrada.
Por exemplo, imagine que você está programando em uma linguagem sem while. Teoricamente, você não precisa de while se você tiver if e goto. Na prática, é conveniente ter uma construção pronta ao invés de escrever o código com if/goto toda vez. Em uma linguagem como C, se o while não for um comando embutido na linguagem, não há o que fazer; para adicionar o while, teríamos que alterar o compilador. Porém, a transformação de um while em um if/goto é trivial, e poderia ser facilmente automatizada:
while (teste) { => loopstart: comando1; if (teste) { comando2; comando1; } comando2; goto loopstart; }
A idéia da macro é permitir ao programador adicionar transformações de código desse tipo à linguagem. Em Common Lisp, a transformação que queremos é:
(while teste => (tagbody loopstart comando1 (when teste comando2) comando1 comando2 (go loopstart))
Essa transformação pode ser expressa com a seguinte macro:
(defmacro while (test &body body) `(tagbody loopstart (when ,test ,@body (go loopstart))))
Embora esse seja um exemplo simples, similar a uma macro localizar-e-substituir, uma macro pode realizar qualquer tipo de transformação no código. A macro é simplesmente uma função que transforma trechos de código em outros trechos de código, e tudo o que pode ser feito por uma função pode ser feito em uma macro. É possível implementar sub-linguagens com macros; por exemplo, poder-se-ia implementar uma macro para converter queries numa sintaxe SQL-like em código correspondente para realizar a query em um banco de dados. (De fato, existem bibliotecas que fazem isso em Common Lisp.) Macros executam em tempo de compilação, e portanto podem ser arbitrariamente complexas sem afetar o desempenho do código em tempo de execução (desde que o código retornado pela macro seja eficiente). As possibilidades são infinitas.
Se você tiver interesse na linguagem, recomendo ler o Practical Common Lisp. Fica o alerta ao leitor: Lisp é um negócio bizarro à primeira vista. Common Lisp, em particular, não é lá muito bonitinho e consistente em alguns aspectos (embora faça muito mais sentido com o tempo do que pode parecer inicialmente). Se você quiser aprender a linguagem a fundo, terá que se aproximar dela com a mente aberta e dar-lhe o benefício da dúvida em algumas ocasiões. Em verdade vos digo: vale muito a pena.
Copyright © 2010-2024 Vítor De Araújo
O conteúdo deste blog, a menos que de outra forma especificado, pode ser utilizado segundo os termos da licença Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International.
Powered by Blognir.