Clojure中的代码生成

时间:2009-10-26 22:10:06

标签: clojure

(免责声明:我是C#家伙。我刚开始学习Clojure。)

我知道Clojure 程序能够自行操作或轻松生成其他程序。它与Clojure中的所有内容有关,它是一种数据结构,生成程序与创建任何其他类型的数据结构相同。

是否有人有一个好的示例程序(或对一个的参考)显示这个?

如果您生成程序,是否可以将该程序“序列化”到磁盘以供以后执行?

仅供参考:

  1. 我正在尝试使用遗传编程。我想生成很多小程序,评估它们,并使用成功的程序来生成更多程序。查看更多herehere

  2. 我想我在这里滥用条款。通过程序我实际上是指一个clojure列表,而代码生成我的意思是“列表生成”。我只需要列表来包含实际的函数调用和参数。我需要能够控制此列表何时“执行”。

5 个答案:

答案 0 :(得分:28)

考虑(+ 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

答案 1 :(得分:5)

Clojure是一个LISP,这意味着它是一种homoiconic语言:数据和代码之间没有结构上的区别。它列出了所有方式。它还有一个可扩展的编译器,允许您通过宏扩展语法。但是你的问题陈述中并不清楚你真的需要这样的东西。

您基本上运行的代码生成列表(实际上是下一代程序),保存它们,然后运行新程序。除非你的世代演变需要新的语法,否则你可能不需要求助于宏。

答案 2 :(得分:4)

this文章中找到了部分答案:

  

prprn功能就像   他们的印刷和印刷对应物,   但他们的输出形式可以   由Clojure读者阅读。他们   适用于序列化Clojure   数据结构。默认情况下,他们这样做   不打印元数据。这可以   通过绑定特殊符号来更改   *print-meta*true

这至少回答了我问题的第二部分。

答案 3 :(得分:3)

这个问题有些误导,因为Clojure在Java字节代码中编译Clojure源时也会执行动态“代码生成”。

在这种特殊情况下,我相信你特别喜欢Lisp Macros。我认为这些可能很有趣:

Clojure documentation itself

Video, Macros (in Clojure) in 20 minutes

Standard issue: Wikipedia - Clojure

请注意,Clojure中的宏与Common Lisp宏(类型为2的lisp)非常相似,并且不太像Scheme宏。

快乐的编码。

答案 4 :(得分:2)

看看宏。例如,

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

使用宏,您不需要序列化宏展开;编译将自动使用它。