你能得到“代码即数据”吗? Clojure 中加载的函数?
换句话说,“好吧,代码就是数据...”
该线程解决了如何从源文件中读取的问题,但我想知道如何将已加载函数的 s 表达式获取到我可以读取和操作的数据结构中。
换句话说,如果我说,
(defn example [a b] (+ a b))
我不能在运行时获取该列表吗?这难道不是“代码即数据”的全部意义吗?
这确实是一个常见的 Lisp 问题,但我正在 Clojure 中寻找答案。
To put it another, way, "Okay, so code is data..."
That thread addresses how to read from a source file, but I'm wondering how to get the s-expression of an already-loaded function into a data structure that I can read and manipulate.
In other words, if I say,
(defn example [a b] (+ a b))
can't I get that list at runtime? Isn't this the whole point of "code as data"?
This is really a general Lisp question, but I'm looking for an answer in Clojure.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您可以使用 clojure.repl/source 宏来获取符号的源:
但这只是答案的一部分。 AFAICT
source
查找定义给定符号的源文件名和行号,然后从文件中打印源代码。因此,source
不适用于您没有源代码的符号,即 AOT 编译的 clojure 代码。回到您最初的问题,您可以将
source
视为读取与给定符号关联的元数据并简单地打印它。即这是作弊。它不会以任何方式将“代码作为数据”返回给您,其中代码是指编译后的 clojure 函数。在我看来,“代码即数据”指的是 lisp 的特性,其中源代码实际上是 lisp 数据结构,因此它可以被 lisp 阅读器读取。也就是说,我可以创建一个作为有效 Lisp 代码的数据结构,并对其进行
eval
。例如:
这里
'(+ 1 1)
是一个文字列表,由 clojure 阅读器读取,然后计算为 clojure 代码。更新: Yehonathan Sharvit 在其中一条评论中询问是否可以修改函数的代码。以下代码片段读取函数的源代码,修改生成的数据结构,最后评估数据结构,从而定义一个新函数
my-nth
: 行将
defn
形式中的nth
替换为my-nth
。You can use the
clojure.repl/source
macro to get the source of a symbol:But this is only part of the answer. AFAICT
source
looks up the source filename and line number that define the given symbol, and then prints the source code from the file. Therefore,source
will not work on symbols that you do not have the source for, i.e. AOT-compiled clojure code.Coming back to your original question, you can think of
source
as reading the meta data associated with the given symbol and simply printing that. I.e. it's cheating. It's not in any way returning "code as data" to you, where with code I mean a compiled clojure function.In my mind "code as data" refers to the feature of lisps where source code is effectively a lisp data structure, and therefore it can be read by the lisp reader. That is, I can create a data structure that is valid lisp code, and
eval
that.For example:
Here
'(+ 1 1)
is a literal list which gets read by the clojure reader and then evaluated as clojure code.Update: Yehonathan Sharvit was asking in one of the comments if it's possible to modify the code for a function. The following snippet reads in the source for a function, modifies the resulting data structure, and finally evaluates the data structure resulting in a new function,
my-nth
, being defined:The
syntax-quote
line replacesnth
withmy-nth
in thedefn
form.您可以使用
source
函数获取最新版本的 clojure 中的源代码。要获取字符串作为值,您可以将其包装在
with-out-str
中:You can get the source in recent versions of clojure with the
source
function.to get the string as a value you can wrap this in
with-out-str
:这就是我的信息;很高兴见到你;-) 顺便说一句,该线程中给出的答案参考资料非常好读;因此,如果您有兴趣,您可能需要花时间阅读它们。回到你的问题,尽管
source
似乎适用于通过文件加载的代码,但它并非在所有情况下都适用。我认为,具体来说,它不适用于 repl 中定义的函数。挖掘一点......
所以是的,看起来它试图从类路径加载源文件以尝试为您吐出它。我在使用 Clojure 时学到的一件事是,十分之九查看源代码是有用的。
That was my message; nice to meet you ;-) BTW, the references given in that thread for answers were excellent reading; so if you're interested, you might want to take the time to read them. Back to your question though
source
seems to work for code that was loaded through a file, but it doesn't work in all cases. I think, specifically, it doesn't work for functions defined in the repl.Digging a little bit...
So yeah, it looks like it tries to load the source file off the classpath to try to spit it out for you. One thing I've learned when working with Clojure is that 9 times out of 10 it is useful to look at the source.