2009-10-26 6 views
15

(Disclaimer:. Sono un C# ragazzo ho appena iniziato ad imparare Clojure.)Generazione di codice in Clojure

Capisco che un programma Clojure ha la capacità di manipolare se stesso o facilmente generare altri programmi . Ha qualcosa a che fare con tutto ciò che in Clojure è una struttura dati e che generare programmi equivale a creare qualsiasi altro tipo di struttura dati.

Qualcuno ha un buon programma di esempio (o un riferimento a uno) che mostra questo?

Se si genera un programma , è possibile "serializzare" il programma su disco per l'esecuzione successiva?

Solo per riferimento:

  1. che sto cercando di giocare con la programmazione genetica. Voglio generare un sacco di piccoli programmi, valutarli e usare quelli di successo per generare più programmi. Vedi di più here e here.

  2. Penso che mi stia abusando dei termini qui. Per il programma Intendo effettivamente un elenco di clojure e per Generazione codice Intendo "Generazione elenco". Ho solo bisogno dell'elenco per contenere chiamate e parametri di funzione effettivi. Dovrei essere in grado di controllare quando questa lista viene "eseguita".

risposta

27

Considerare (+ 1 2). Come dati, è un elenco collegato di tre elementi: il Simbolo + e due numeri interi. Come codice, è una chiamata di funzione, che dice "Chiama la funzione chiamata + con questi due Integri come argomenti e dammi il risultato". Puoi fare qualsiasi cosa in questo elenco che puoi fare con qualsiasi altro elenco di dati. È possibile anche eval per ottenere un risultato.

user> (def x '(+ 1 2)) 
#'user/x 
user> (first x) 
+ 
user> (rest x) 
(1 2) 
user> (map class x) 
(clojure.lang.Symbol java.lang.Integer java.lang.Integer) 
user> (reverse x) 
(2 1 +) 
user> (concat x (rest x)) 
(+ 1 2 1 2) 
user> (eval x) 
3 
user> (defn foo [] 
     (let [ops '[+ - * /]    ; SO's lisp-highlighting sucks 
       nums (repeatedly #(rand-int 5)) 
       expr (list* (rand-elt ops) (take 10 nums))] 
      (prn expr) 
      (prn (eval expr)))) 
user> (foo) 
(+ 4 1 0 3 2 3 4 3 1 2) 
23 
nil 
user> (foo) 
(- 1 3 2 2 1 2 1 4 0 1) 
-15 
nil 
4

trovato una risposta parziale this articolo:

Il pr e prn funzioni sono come loro stampa e omologhi println, ma la loro produzione è in una forma che può leggibile dal Lettore Clojure. Sono adatti per la serializzazione delle strutture dati Clojure . Per impostazione predefinita, fanno non stampare i metadati. Questo può essere modificato legando il simbolo speciale *print-meta* a true.

Questo almeno risponde alla seconda parte della mia domanda.

2

Dai un'occhiata alle macro. Ad esempio,

(defmacro defmacro- 
    "Same as defmacro but yields a private definition" 
    [name & decls] 
    (list* `defmacro (with-meta name (assoc (meta name) :private true)) decls)) 

Con i macro, non è necessario serializzare la macroespansione; la compilazione la userà automaticamente.

5

Clojure è un LISP e ciò significa che è una lingua homoiconic: non esiste una distinzione strutturale tra dati e codice. Le sue liste fino in fondo. Ha anche un compilatore estensibile che consente di estendere la sintassi tramite macro. Ma non è chiaro dalla tua affermazione sul problema che hai davvero bisogno di una cosa del genere.

In pratica stai eseguendo il codice che genera elenchi (che sono in realtà programmi next gen), salvandoli e quindi eseguendo i nuovi programmi. A meno che la tua evoluzione generazionale richieda una nuova sintassi, probabilmente non avrai bisogno di ricorrere ai macro.

+0

Questo è esattamente quello che sto cercando! Se capisco correttamente, ogni "programma" sarà una lista. Ho solo bisogno di un modo per "generare" quella lista con chiamate e parametri di funzione e quindi "eseguire" quella lista una volta che ho finito. Penso che ho solo bisogno di generare la lista preceduta da una citazione, in modo che la lista non sia "valutata". –

+0

Esattamente. Dovresti leggere e capire questa pagina: http://clojure.org/reader – alphazero

3

La domanda è in qualche modo fuorviante poiché Clojure esegue anche "la generazione di codice" al volo mentre compila l'origine Clojure nel codice byte Java.

In questo caso particolare, credo che siate particolarmente interessanti nei macro Lisp. Penso che questi possono essere interessanti:

Clojure documentation itself

Video, Macros (in Clojure) in 20 minutes

Standard issue: Wikipedia - Clojure

Si noti che le macro in Clojure lavorano molto simile alle macro Common Lisp (un tipo-2 lisp), e non Macro molto simili a Scheme.

Felice codifica.

+0

Ricorda, sono un ragazzo di C#. Sto assolutamente abusando del termine "Generazione del codice" qui. Penso che quello che sto cercando di dire è "Generazione elenco", ma l'elenco deve contenere chiamate di funzione effettive. –