har*_*rpo 10 reflection clojure
换句话说," 好的,所以代码就是数据...... "
该线程解决了如何从源文件中读取,但我想知道如何将已经加载的函数的s表达式转换为我可以读取和操作的数据结构.
换句话说,如果我说,
(defn example [a b] (+ a b))
Run Code Online (Sandbox Code Playgroud)
我不能在运行时获得该列表?这不是"代码作为数据"的全部意义吗?
这实际上是一个普遍的Lisp问题,但我正在寻找Clojure的答案.
您可以使用clojure.repl/source
宏来获取符号的来源:
user> (source max)
(defn max
"Returns the greatest of the nums."
{:added "1.0"
:inline-arities >1?
:inline (nary-inline 'max)}
([x] x)
([x y] (. clojure.lang.Numbers (max x y)))
([x y & more]
(reduce1 max (max x y) more)))
nil
Run Code Online (Sandbox Code Playgroud)
但这只是答案的一部分.AFAICT source
查找定义给定符号的源文件名和行号,然后从文件中打印源代码.因此,source
不适用于您没有源代码的符号,即AOT编译的clojure代码.
回到原始问题,您可以将其source
视为读取与给定符号关联的元数据并简单地打印它.即它是作弊.它不会以任何方式将"代码作为数据"返回给您,其中代码我的意思是编译的clojure函数.
在我看来,"作为数据的代码"指的是lisps的特性,其中源代码实际上是一个lisp数据结构,因此它可以被lisp阅读器读取.也就是说,我可以创建一个有效的lisp代码的数据结构eval
.
例如:
user=> (eval '(+ 1 1))
2
Run Code Online (Sandbox Code Playgroud)
这'(+ 1 1)
是一个文字列表,由clojure读者读取,然后作为clojure代码进行评估.
更新: Yehonathan Sharvit在其中一条评论中询问是否可以修改函数的代码.下面的代码片段读取函数的源代码,修改生成的数据结构,最后评估导致新函数的数据结构my-nth
,定义如下:
(eval
(let [src (read-string (str (source-fn 'clojure.core/nth) "\n"))]
`(~(first src) my-nth ~@(nnext src))))
Run Code Online (Sandbox Code Playgroud)
该syntax-quote
行替换nth
用my-nth
的defn
形式.