Clojure中的代码生成
(免责声明:我是一名C#guy。我刚刚开始学习Clojure。) 我知道Clojure程序能够自行操作或轻松生成其他程序。它与Clojure中的所有内容都是数据结构有关,生成程序与创建任何其他类型的数据结构都是一样的 有没有人有一个很好的示例程序(或对它的引用)来说明这一点 如果生成一个程序,能否将该程序“序列化”到磁盘以供以后执行 仅供参考:Clojure中的代码生成,clojure,Clojure,(免责声明:我是一名C#guy。我刚刚开始学习Clojure。) 我知道Clojure程序能够自行操作或轻松生成其他程序。它与Clojure中的所有内容都是数据结构有关,生成程序与创建任何其他类型的数据结构都是一样的 有没有人有一个很好的示例程序(或对它的引用)来说明这一点 如果生成一个程序,能否将该程序“序列化”到磁盘以供以后执行 仅供参考: 我想玩遗传编程。我想生成许多小程序,对它们进行评估,并使用成功的程序生成更多的程序。看到更多和更多 我想我在这里误用了术语。我所说的程序实际上是指clo
pr
和prn
功能如下
他们的印刷品和印刷品副本,
但它们的输出形式可以
被Clojure的读者阅读。他们
适用于序列化Clojure
数据结构。默认情况下,他们会这样做
不打印元数据。这可能是
通过绑定特殊符号进行更改
*将meta*
打印为true
这至少回答了我问题的第二部分。看看宏。比如说,
(defmacro defmacro-
"Same as defmacro but yields a private definition"
[name & decls]
(list* `defmacro (with-meta name (assoc (meta name) :private true)) decls))
对于宏,您不需要序列化宏扩展;编译将自动使用它。Clojure是一种LISP,这意味着它是一种语言:数据和代码之间没有结构上的区别。它的清单一路向下。它还有一个可扩展的编译器,允许您通过宏扩展语法。但从你的问题陈述来看,你并不清楚你真的需要这样的东西
您基本上是在运行生成列表(实际上是下一代程序)的代码,保存它们,然后运行新程序。除非您的世代进化需要新的语法,否则您可能不需要求助于宏。这个问题有些误导,因为Clojure在用Java字节码编译Clojure源代码时也会执行动态“代码生成” 在本例中,我相信您对Lisp宏特别感兴趣。我认为这些可能很有趣: 请注意,Clojure中的宏与常见的Lisp宏(2型Lisp)非常相似,与Scheme宏不太相似 快乐的编码。考虑一下
(+12)
。作为数据,它是一个由三项组成的链表:符号+
和两个整数。作为代码,它是一个函数调用,表示“使用这两个整数作为参数调用名为+
的函数,并给出结果”。您可以对该列表执行任何操作,也可以对任何其他数据列表执行任何操作。您还可以eval
it以获得结果
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
这正是我想要的!如果我理解正确,每个“程序”都将是一个列表。我只需要一种方法,用函数调用和参数“生成”该列表,然后在完成后“执行”该列表。我想我只需要生成一个以引号为前缀的列表,这样列表就不会被“评估”。你会想阅读并理解这一页:记住,我是一个C#guy。我在这里肯定误用了“代码生成”这个术语。我想我真正想说的是“列表生成”,但是列表需要包含实际的函数调用。