Existem muitos idiomas que permitem algum tipo de metaprogramação .
Em particular, estou surpreso em não ver nenhuma resposta sobre a família de idiomas Lisp .
Da wikipedia:
Metaprogramming is the writing of computer programs with the ability
to treat programs as their data.
Mais tarde no texto:
Lisp is probably the quintessential language with metaprogramming
facilities, both because of its historical precedence and because of
the simplicity and power of its metaprogramming.
Idiomas Lisp
Uma introdução rápida feita para Lisp segue.
Uma maneira de ver o código é como um conjunto de instruções: faça isso, faça isso, faça outra coisa ... Esta é uma lista! Uma lista de coisas para o programa fazer. E, claro, você pode ter listas dentro de listas para representar loops e assim por diante.
Se representarmos uma lista contendo os elementos a, b, c, d assim: (abcd) obtemos algo que se parece com uma chamada de função Lisp, em que a
é a função e b
, c
, d
são os argumentos.
Se fato o típico "Olá mundo!" programa poderia ser escrito da seguinte forma: (println "Hello World!")
É claro que b
, c
ou d
podem ser listas que também avaliam algo. O seguinte: (println "I can add :" (+ 1 3) )
imprimiria "" Eu posso adicionar: 4 ".
Assim, um programa é uma série de listas aninhadas, e o primeiro elemento é uma função. A boa notícia é que podemos manipular listas! Então, podemos manipular linguagens de programação.
A vantagem do Lisp
Lisps are not so much programming languages as much as a toolkit for making programming languages. A programmable programming language.
Isso não só é muito mais fácil em Lisps para criar novos operadores, como também é quase impossível escrever alguns operadores em outras linguagens porque os argumentos são avaliados quando passados para a função.
Por exemplo, em uma linguagem semelhante a C, digamos que você queira escrever um operador if
, algo como:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
Neste caso, ambos os argumentos serão avaliados e impressos, em uma ordem dependente da ordem de avaliação dos argumentos.
Em Lisps, escrever um operador (chamamos de macro) e escrever uma função é praticamente a mesma coisa e usada da mesma maneira. A principal diferença é que os parâmetros para uma macro são nã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, mas eu encorajo você a tentar programar em um Lisp para aprender mais. Por exemplo, você poderia dar uma olhada:
-
Esquema , um velho Lisp bastante "puro" com um pequeno núcleo
- Common Lisp, um Lisp maior com um sistema de objetos bem integrado e muitas implementações (é padronizado pela ANSI)
-
Racket um Lisp digitado
-
Clojure meu favorito, os exemplos acima eram código de Clojure. Um moderno Lisp rodando na JVM. Existem alguns exemplos de macros Clojure em SO (mas este não é o lugar certo para começar. Eu gostaria de ver 4clojure , braveclojure ou koans clojure no início)).
Ah, e a propósito, Lisp significa Processamento de LISt.
Em relação aos seus exemplos
Vou dar exemplos usando o Clojure abaixo:
Se você pode escrever uma função add
em Clojure (defn add [a b] ...your-implementation-here... )
, você pode nomear +
como (defn + [a b] ...your-implementation-here... )
. Isto é, de fato, o que é feito no real implementação (o corpo da função é um pouco mais envolvido, mas a definição é essencialmente a mesma que escrevi acima).
E quanto à notação infixada? Bem, o Clojure usa uma notação prefix
(ou polonês), portanto, poderíamos criar uma macro infix-to-prefix
que transformaria o código prefixado em código Clojure.
O que na verdade é surpreendentemente fácil (na verdade, é um dos exercícios de macro nos koans clojure)! Também pode ser visto na natureza, por exemplo, consulte Incanter $=
macro .
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 impulsionar ainda mais o ponto, algumas citações de Lisp :
“Part of what makes Lisp distinctive is that it is designed to evolve.
You can use Lisp to define new Lisp operators. As new abstractions
become popular (object-oriented programming, for example), it always
turns out to be easy to implement them in Lisp. Like DNA, such a
language does not go out of style.”
— Paul Graham, ANSI Common Lisp
“Programming in Lisp is like playing with the primordial forces of the
universe. It feels like lightning between your fingertips. No other
language even feels close.”
— Glenn Ehrlich, Road to Lisp