Question

(Avertissement: je suis un homme C #. Je viens juste d'apprendre à apprendre Clojure.)

Je comprends qu'un programme Clojure a la capacité de se manipuler ou de générer facilement d'autres programmes . . Cela a quelque chose à voir avec le fait que tout dans Clojure est une structure de données et que générer des programmes équivaudrait à créer tout autre type de structure de données.

Quelqu'un at-il un bon exemple de programme (ou une référence à un programme) qui le montre?

Si vous générez un programme , pouvez-vous "sérialiser" " ce programme sur le disque pour une exécution ultérieure?

Juste pour référence:

  1. J'essaie de jouer avec la programmation génétique. Je veux générer beaucoup de petits programmes, les évaluer et utiliser ceux qui ont réussi pour générer plus de programmes. Voir plus ici et ici .

  2. Je pense que je fais un mauvais usage des termes ici. Par programme , j'entends en fait une liste de clojure et par Génération de code , je parle de "Génération de liste". J'ai juste besoin que la liste contienne les appels de fonction et les paramètres. J'aurais besoin de pouvoir contrôler quand cette liste sera "exécutée".

Était-ce utile?

La solution

Considérons (+ 1 2) . En tant que données, il s'agit d'une liste chaînée de trois éléments: le symbole + et deux nombres entiers. En tant que code, il s’agit d’un appel de fonction disant "Appelez la fonction + avec ces deux nombres entiers comme arguments et donnez-moi le résultat". Vous pouvez faire quelque chose à cette liste que vous pouvez faire à n'importe quelle autre liste de données. Vous pouvez également eval pour obtenir un résultat.

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

Autres conseils

Clojure est un LISP, ce qui signifie qu'il s'agit d'une langue homoiconic : il n'y a pas distinction structurelle entre données et code. Ses listes tout en bas. Il dispose également d'un compilateur extensible qui vous permet d'étendre la syntaxe à l'aide de macros. Toutefois, votre énoncé du problème ne dit pas clairement que vous avez vraiment besoin d’une telle chose.

Vous exécutez un code qui génère des listes (qui sont vraiment des programmes de la prochaine génération), vous les enregistrez, puis vous exécutez les nouveaux programmes. À moins que votre évolution générationnelle nécessite une nouvelle syntaxe, vous n’auriez probablement pas besoin de recourir aux macros.

Vous avez trouvé une réponse partielle dans cet article :

  

Les fonctions pr et prn sont comme   leurs contreparties imprimées et imprimées,   mais leur sortie est sous une forme qui peut   être lu par le lecteur Clojure. Ils   conviennent à la sérialisation de Clojure   structures de données. Par défaut, ils font   pas imprimer les métadonnées. Cela peut être   changé en liant le symbole spécial    * print-meta * en true .

Cela répond au moins à la deuxième partie de ma question.

La question est quelque peu trompeuse, car Clojure effectue également à la volée "la génération de code". lorsqu’il compile la source Clojure en Java Byte Code.

Dans ce cas particulier, je pense que vous êtes intéressé par les macros Lisp en particulier. Je pense que ceux-ci peuvent être intéressants:

La documentation Clojure elle-même

Vidéo, Macros (in Clojure) dans 20 minutes

Édition standard: Wikipedia - Clojure

Notez que les macros dans Clojure fonctionnent de manière très similaire aux macros Common Lisp (un lisp de type 2) et à des macros scheme pas trop similaires.

Joyeux codage.

Regardez les macros. Par exemple,

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

Avec les macros, vous n'avez pas besoin de sérialiser la macroexpansion; la compilation l'utilisera automatiquement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top