Esistono molte lingue che consentono un tipo di metaprogramming .
In particolare, sono sorpreso di vedere nessuna risposta parlando della Lisp famiglia di lingue.
Da wikipedia:
Metaprogramming is the writing of computer programs with the ability
to treat programs as their data.
Più tardi nel testo:
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.
Lingue Lisp
Segue una breve introduzione inventata a Lisp.
Un modo per vedere il codice è come una serie di istruzioni: fai questo, poi fallo, poi fai quest'altra cosa ... Questa è una lista! Una lista di cose da fare per il programma. E ovviamente puoi avere liste all'interno di liste per rappresentare loop e così via ...
Se rappresentiamo una lista contenente gli elementi a, b, c, d in questo modo: (abcd) otteniamo qualcosa che assomiglia a una chiamata di funzione Lisp, dove a
è la funzione e b
, c
, d
sono gli argomenti.
Se è vero il tipico "Hello World!" il programma potrebbe essere scritto in questo modo: (println "Hello World!")
Ovviamente b
, c
o d
potrebbero essere elenchi che valutano anche qualcosa. Quanto segue: (println "I can add :" (+ 1 3) )
quindi stampa "" Posso aggiungere: 4 ".
Quindi, un programma è una serie di liste annidate e il primo elemento è una funzione. La buona notizia è che possiamo manipolare le liste! Quindi possiamo manipolare i linguaggi di programmazione.
Il vantaggio Lisp
Lisps are not so much programming languages as much as a toolkit for making programming languages. A programmable programming language.
Questo non è solo molto più facile in Lisps per creare nuovi operatori, è anche quasi impossibile scrivere alcuni operatori in altre lingue perché gli argomenti vengono valutati quando vengono passati alla funzione.
Per esempio in un linguaggio simile a C diciamo che vuoi scrivere un operatore if
tu stesso, qualcosa del tipo:
my-if(condition, if-true, if-false)
my-if(false, print("I should not be printed"), print("I should be printed"))
In questo caso entrambi gli argomenti saranno valutati e stampati, in un ordine dipendente dall'ordine di valutazione degli argomenti.
In Lisps, scrivere un operatore (noi lo chiamiamo macro) e scrivere una funzione è circa la stessa cosa e usato allo stesso modo. La principale differenza è che i parametri di una macro sono non valutati prima di essere passati come argomenti alla macro. Questo è essenziale per poter scrivere alcuni operatori, come if
sopra.
Lingue reali
Mostra quanto esattamente è un po 'fuori portata qui, ma ti incoraggio a provare a programmare in un Lisp per saperne di più. Ad esempio potresti dare un'occhiata a:
-
Scheme , un Lisp vecchio, abbastanza "puro" con un piccolo nucleo
- Common Lisp, un Lisp più grande con un sistema di oggetti ben integrato e molte implementazioni (è standardizzato ANSI)
-
Racket un Lisp digitato
-
Clojure il mio preferito, gli esempi sopra erano codice Clojure. Un Lisp moderno in esecuzione sulla JVM. Ci sono alcuni esempi di macro Clojure su SO (ma questo non è il posto giusto per iniziare. 4clojure , braveclojure o clojure koans all'inizio)).
Oh, a proposito, Lisp significa elaborazione LISt.
Riguardo ai tuoi esempi
Fornirò degli esempi usando Clojure di seguito:
Se puoi scrivere una funzione add
in Clojure (defn add [a b] ...your-implementation-here... )
, puoi chiamarla +
come (defn + [a b] ...your-implementation-here... )
. Questo è in effetti ciò che viene fatto nel reale implementazione (il corpo della funzione è un po 'più coinvolto, ma la definizione è essenzialmente la stessa di cui ho scritto sopra).
E la notazione infix? Well Clojure usa una notazione prefix
(o Polish), quindi potremmo creare una macro infix-to-prefix
che trasformerebbe il codice prefissato in codice Clojure.
Che è in realtà sorprendentemente facile (in realtà è uno dei esercizi macro nei koan del clojure)! Può anche essere visto in natura, ad esempio vedi Incanter $=
macro .
Ecco la versione più semplice dei koans spiegata:
(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
Per aumentare ulteriormente il punteggio, alcune virgolette 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