Pergunta
(Disclaimer: Eu sou um cara C # Eu apenas comecei aprendendo Clojure..)
Eu entendo que um Clojure programa tem a capacidade de manipular a si mesmo ou facilmente gerar outros programas . Tem algo a ver com tudo em Clojure sendo uma estrutura de dados e que a geração de programas seria o mesmo que criar qualquer outro tipo de estrutura de dados.
Alguém tem um bom programa de amostra (ou uma referência a um) que mostra isso?
Se você gerar um programa , não é "serialize" esse programa no disco para execução posterior?
Apenas para referência:
-
Eu estou tentando jogar com Programação Genética. Eu quero gerar um monte de pequenos programas, avaliá-los e usar os bem-sucedidos para gerar mais programas. Ver mais aqui e aqui .
-
Eu acho que estou abusando termos aqui. Por programa eu realmente significam uma lista clojure e pela Geração de código eu quero dizer "Lista Generation". Eu só preciso a lista para conter chamadas de funções reais e parâmetros. Eu preciso ser capaz de controlar quando esta lista é "executado".
Solução
Considere (+ 1 2)
. Conforme os dados, é uma lista encadeada de três itens: a +
símbolo e dois inteiros. Como código, é uma chamada de função, dizendo "Ligue para a função chamada +
com esses dois inteiros como argumentos e me dar o resultado". Você pode fazer qualquer coisa a esta lista que você pode fazer para qualquer outra lista de dados. Você também pode eval
-lo para obter um resultado.
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
Outras dicas
Clojure é um LISP, e isso significa que é um homoiconic língua: não existe distinção estrutural entre os dados e o código. Suas listas de todo o caminho. Ele também tem um compilador extensível que permite estender a sintaxe através de macros. Mas não é claro a partir de sua declaração de problema que você realmente precisa de uma coisa dessas.
Você está correndo basicamente código que gera listas (que são realmente próximos programas gen), salvando-os, em seguida, executar os novos programas. A menos que sua evolução geracional exigirá nova sintaxe, você provavelmente não precisa de recorrer a macros.
Encontrado uma resposta parcial em este artigo :
As funções
pr
eprn
são como sua impressão e contrapartes println, mas a sua saída está em um formulário que pode ser lido pelo leitor Clojure. Eles são adequados para a serialização Clojure estruturas de dados. Por padrão, eles fazem Não imprimir metadados. Isso pode ser mudou ligando o símbolo especial*print-meta*
paratrue
.
Esta, pelo menos, respostas a segunda parte da minha pergunta.
A questão é um pouco enganador como Clojure também realiza "geração de código" on-the-fly, uma vez que compila fonte Clojure em Java Código Byte.
Neste caso particular, Eu acredito você é interessante em Lisp macros em particular. Eu acho que estes podem ser interessantes:
documentaçãoVídeo, Macros (em Clojure) em 20 minutos
questão Standard: Wikipedia - Clojure
Note que as macros no trabalho Clojure muito semelhante para macros Lisp Comum (um tipo-2 Lisp), e não é bem-assim-muito-como macros Esquema.
Happy codificação.
Dê uma olhada em macros. Por exemplo,
(defmacro defmacro-
"Same as defmacro but yields a private definition"
[name & decls]
(list* `defmacro (with-meta name (assoc (meta name) :private true)) decls))
Com macros, você não precisa para serializar o macroexpansion; a compilação irá usá-lo automaticamente.