【发布时间】:2009-10-26 22:10:06
【问题描述】:
(免责声明:我是 C# 人。我刚刚开始学习 Clojure。)
我了解 Clojure 程序 具有操纵自身或轻松生成其他程序 的能力。这与 Clojure 中的所有内容都是数据结构有关,生成 程序 与创建任何其他类型的数据结构相同。
有没有人有一个很好的示例程序(或一个参考)来说明这一点?
如果你生成一个程序,你能把那个程序“序列化”到磁盘上供以后执行吗?
仅供参考:
【问题讨论】:
标签: clojure
(免责声明:我是 C# 人。我刚刚开始学习 Clojure。)
我了解 Clojure 程序 具有操纵自身或轻松生成其他程序 的能力。这与 Clojure 中的所有内容都是数据结构有关,生成 程序 与创建任何其他类型的数据结构相同。
有没有人有一个很好的示例程序(或一个参考)来说明这一点?
如果你生成一个程序,你能把那个程序“序列化”到磁盘上供以后执行吗?
仅供参考:
【问题讨论】:
标签: clojure
考虑(+ 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
【讨论】:
Clojure 是一种 LISP,这意味着它是一种homoiconic 语言:数据和代码之间没有结构上的区别。它的列表一直向下。它还有一个可扩展的编译器,允许您通过宏扩展语法。但是从你的问题陈述中并不清楚你真的需要这样的东西。
您基本上是在运行生成列表的代码(实际上是下一代程序)、保存它们,然后运行新程序。除非您的世代进化需要新语法,否则您可能不需要求助于宏。
【讨论】:
在this文章中找到了部分答案:
pr和prn函数就像 他们的 print 和 println 对应物, 但他们的输出形式可以 由 Clojure 阅读器阅读。他们 适合序列化 Clojure 数据结构。默认情况下,他们会 不打印元数据。这可以是 通过绑定特殊符号更改*print-meta*到true。
这至少回答了我问题的第二部分。
【讨论】:
这个问题有些误导,因为 Clojure 还在 Java 字节码中编译 Clojure 源代码时执行动态“代码生成”。
在这种特殊情况下,我相信你对 Lisp 宏特别感兴趣。我认为这些可能很有趣:
Video, Macros (in Clojure) in 20 minutes
Standard issue: Wikipedia - Clojure
请注意,Clojure 中的宏与 Common Lisp 宏(类型 2 lisp)的工作方式非常相似,而不是非常像 Scheme 宏。
编码愉快。
【讨论】:
看看宏。例如,
(defmacro defmacro-
"Same as defmacro but yields a private definition"
[name & decls]
(list* `defmacro (with-meta name (assoc (meta name) :private true)) decls))
使用宏,您不需要序列化宏扩展;编译会自动使用它。
【讨论】: