(免责声明:我是C#家伙。我刚开始学习Clojure。)
我知道Clojure 程序能够自行操作或轻松生成其他程序。它与Clojure中的所有内容有关,它是一种数据结构,生成程序与创建任何其他类型的数据结构相同。
是否有人有一个好的示例程序(或对一个的参考)显示这个?
如果您生成程序,是否可以将该程序“序列化”到磁盘以供以后执行?
仅供参考:
答案 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文章中找到了部分答案:
pr
和prn
功能就像 他们的印刷和印刷对应物, 但他们的输出形式可以 由Clojure读者阅读。他们 适用于序列化Clojure 数据结构。默认情况下,他们这样做 不打印元数据。这可以 通过绑定特殊符号来更改*print-meta*
至true
。
这至少回答了我问题的第二部分。
答案 3 :(得分:3)
这个问题有些误导,因为Clojure在Java字节代码中编译Clojure源时也会执行动态“代码生成”。
在这种特殊情况下,我相信你特别喜欢Lisp Macros。我认为这些可能很有趣:
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))
使用宏,您不需要序列化宏展开;编译将自动使用它。