Генерация кода в Clojure - PullRequest
15 голосов
/ 27 октября 2009

(Отказ от ответственности: я парень на C #. Я только начал изучать Clojure.)

Я понимаю, что программа Clojure имеет возможность манипулировать собой или легко создавать другие программы . Это имеет отношение к тому, что в Clojure все является структурой данных, и генерация программ будет такой же, как и создание любого другого типа структуры данных.

У кого-нибудь есть хороший пример программы (или ссылка на нее), которая показывает это?

Если вы сгенерируете программу , вы можете "сериализовать" эту программу на диск для последующего выполнения?

Только для справки:

  1. Я пытаюсь играть с генетическим программированием. Я хочу создавать много маленьких программ, оценивать их и использовать успешные для создания большего количества программ. Подробнее здесь и здесь .

  2. Я думаю, что я здесь неправильно использую термины. Под программой я на самом деле имею в виду закрывающий список, а под генерацией кода я подразумеваю «Генерация списка». Мне просто нужно, чтобы список содержал реальные вызовы функций и параметры. Мне нужно было бы иметь возможность контролировать, когда этот список будет «выполнен».

Ответы [ 5 ]

28 голосов
/ 27 октября 2009

Рассмотрим (+ 1 2). Как данные, это связанный список из трех элементов: Символ + и два целых числа. Как код, это вызов функции, который говорит: «Вызови функцию с именем +, используя эти два целых числа в качестве аргументов и дай мне результат» Вы можете сделать с этим списком все, что вы можете сделать с любым другим списком данных. Вы также можете eval получить результат.

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
5 голосов
/ 27 октября 2009

Clojure - это LISP, а это означает, что это гомоиконичный язык: структурных различий между данными и кодом нет. Его списки полностью вниз. Он также имеет расширяемый компилятор, который позволяет расширять синтаксис с помощью макросов. Но из вашей постановки проблемы не ясно, что вам это действительно нужно.

Вы в основном запускаете код, который генерирует списки (которые на самом деле являются программами следующего поколения), сохраняет их и затем запускаете новые программы. Если для эволюции вашего поколения не потребуется новый синтаксис, вам, вероятно, не придется прибегать к макросам.

4 голосов
/ 27 октября 2009

Нашли частичный ответ в этой статье:

Функции pr и prn похожи их печатные и печатные аналоги, но их вывод находится в форме, которая может быть прочитанным читателем Clojure. Oни подходят для сериализации Clojure структуры данных. По умолчанию они делают не печатать метаданные. Это может быть изменено связыванием специального символа *print-meta* до true.

Это по крайней мере отвечает на вторую часть моего вопроса.

3 голосов
/ 27 октября 2009

Этот вопрос несколько вводит в заблуждение, поскольку Clojure также выполняет «генерацию кода» на лету, поскольку он компилирует исходный код Clojure в байт-код Java.

В данном конкретном случае, Я полагаю, вы особенно интересны в макросах Lisp. Я думаю, что это может быть интересно:

Сама документация Clojure

Видео, макросы (в Clojure) за 20 минут

Стандартный выпуск: Википедия - Clojure

Обратите внимание, что макросы в Clojure очень похожи на макросы Common Lisp (lisp типа 2) и не очень похожи на макросы Scheme.

Счастливого кодирования.

2 голосов
/ 27 октября 2009

Посмотрите на макросы. Например,

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

С макросами вам не нужно сериализовать макроразложение; компиляция будет использовать его автоматически.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...