Existem muitos idiomas que permitem algum tipo de metaprogramação . Surpreende-me, em particular, por não encontrar respostas sobre a família de idiomas Lisp .
Da wikipedia:
Metaprogramação é a escrita de programas de computador com a capacidade de tratar programas como seus dados.
Mais adiante no texto:
O Lisp é provavelmente a linguagem por excelência com recursos de metaprogramação, tanto por sua precedência histórica quanto pela simplicidade e poder de sua metaprogramação.
Línguas Lisp
Uma rápida introdução inventada para Lisp segue.
Uma maneira de ver o código é como um conjunto de instruções: faça isso, depois faça isso e faça outra coisa ... Esta é uma lista! Uma lista de coisas para o programa fazer. E é claro que você pode ter listas dentro de listas para representar loops e assim por diante.
Se nós representamos uma lista contendo os elementos a, b, c, d como este: (ABCD) obtemos algo que se parece com uma chamada de função Lisp, onde a
é a função, e b
, c
, d
são os argumentos. Se fato o típico "Olá Mundo!" programa poderia ser escrito assim:(println "Hello World!")
Obviamente b
, c
ou d
podem ser listas que avaliam algo também. O seguinte: (println "I can add :" (+ 1 3) )
imprimiria "" posso adicionar: 4 ".
Portanto, um programa é uma série de listas aninhadas e o primeiro elemento é uma função. A boa notícia é que podemos manipular listas! Para que possamos manipular linguagens de programação.
A vantagem do Lisp
Lisps não são tanto linguagens de programação quanto um kit de ferramentas para criar linguagens de programação. Uma linguagem de programação programável.
Isso não é apenas muito mais fácil no Lisps para criar novos operadores, também é quase impossível escrever alguns operadores em outros idiomas porque os argumentos são avaliados quando passados para a função.
Por exemplo, em uma linguagem C, digamos que você queira escrever um if
operador, algo como:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
Nesse caso, os dois argumentos serão avaliados e impressos, em uma ordem dependente da ordem de avaliação dos argumentos.
No Lisps, escrever um operador (chamamos de macro) e escrever uma função são sobre a mesma coisa e são usados da mesma maneira. A principal diferença é que os parâmetros para uma macro não são avaliados antes de serem passados como argumentos para a macro. Isso é essencial para poder escrever alguns operadores, como o if
acima.
Idiomas do mundo real
Mostrando exatamente como está um pouco fora do escopo aqui, mas encorajo você a tentar programar em um Lisp para saber mais. Por exemplo, você pode dar uma olhada em:
- Scheme , um antigo Lisp bastante "puro" com um pequeno núcleo
- Lisp comum, um Lisp maior com um sistema de objetos bem integrado e muitas implementações (é padronizado por ANSI)
- Raquete de um Lisp digitado
- Clojure meu favorito, os exemplos acima foram o código Clojure. Um Lisp moderno em execução na JVM. Também existem alguns exemplos de macros Clojure no SO (mas este não é o lugar certo para começar. Eu examinaria os koans 4clojure , braveclojure ou clojure no início).
Ah, a propósito, Lisp significa LISt Processing.
Em relação aos seus exemplos
Vou dar exemplos usando o Clojure abaixo:
Se você pode escrever uma add
função no Clojure (defn add [a b] ...your-implementation-here... )
, pode nomeá-la +
assim (defn + [a b] ...your-implementation-here... )
. Na verdade, é isso que é feito na implementação real (o corpo da função é um pouco mais envolvido, mas a definição é essencialmente a mesma que escrevi acima).
E a notação infix? Bem, o Clojure usa uma prefix
notação (ou polonesa), para que pudéssemos criar uma infix-to-prefix
macro que transformasse o código prefixado em código Clojure. O que é surpreendentemente fácil (na verdade, é um dos exercícios de macro nos koans do clojure)! Também pode ser visto na natureza, por exemplo, veja a macro Incanter$=
.
Aqui está a versão mais simples dos koans explicados:
(defmacro infix [form]
(list (second form) (first form) (nth form 2)))
;; takes a form (ie. some code) as parameter
;; and returns a list (ie. some other code)
;; where the first element is the second element from the original form
;; and the second element is the first element from the original form
;; and the third element is the third element from the original form (indexes start at 0)
;; example :
;; (infix (9 + 1))
;; will become (+ 9 1) which is valid Clojure code and will be executed to give 10 as a result
Para aprofundar ainda mais, algumas citações do Lisp :
“Parte do que torna o Lisp diferenciado é que ele é projetado para evoluir. Você pode usar o Lisp para definir novos operadores Lisp. À medida que novas abstrações se tornam populares (programação orientada a objetos, por exemplo), sempre é fácil implementá-las no Lisp. Como o DNA, essa linguagem não sai de moda. ”
- Paul Graham, ANSI Common Lisp
“Programar em Lisp é como brincar com as forças primordiais do universo. Parece um raio entre as pontas dos dedos. Nenhuma outra língua parece próxima.
- Glenn Ehrlich, estrada para Lisp