[英]How can I display the definition of a function in Clojure at the REPL?
I'm looking for the ability to have the REPL print the current definition of a function. 我正在寻找能够让REPL打印出函数的当前定义的能力。 Is there any way to do this?
有没有办法做到这一点?
For example, given: 例如,给定:
(defn foo [] (if true "true"))
I'd like to say something like 我想说点什么
(print-definition foo)
and get something along the lines of 并得到一些东西
(foo [] (if true "true"))
printed. 打印。
An alternative to source
(which should be available via clojure.repl/source
when starting a REPL, as of 1.2.0
. If you're working with 1.1.0
or lower, source
is in clojure.contrib.repl-utils
.), for REPL use, instead of looking at functions defined in a .clj
file: source
的替代方法(在启动REPL时应该通过clojure.repl/source
,从1.2.0
。如果你使用的是1.1.0
或更低版本,则source
在clojure.contrib.repl-utils
。) ,对于REPL使用,而不是查看.clj
文件中定义的函数:
(defmacro defsource
"Similar to clojure.core/defn, but saves the function's definition in the var's
:source meta-data."
{:arglists (:arglists (meta (var defn)))}
[fn-name & defn-stuff]
`(do (defn ~fn-name ~@defn-stuff)
(alter-meta! (var ~fn-name) assoc :source (quote ~&form))
(var ~fn-name)))
(defsource foo [a b] (+ a b))
(:source (meta #'foo))
;; => (defsource foo [a b] (+ a b))
A simple print-definition
: 一个简单的
print-definition
:
(defn print-definition [v]
(:source (meta v)))
(print-definition #'foo)
#'
is just a reader macro , expanding from #'foo
to (var foo)
: #'
只是一个读者宏 ,从#'foo
扩展到(var foo)
:
(macroexpand '#'reduce)
;; => (var reduce)
You'll want to import the repl
namespace, and use the source
function from it: 您将要导入
repl
名称空间,并使用它的source
函数:
(ns myns
(:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)
=> (foo [] (if true "true"))
nil
Though this wouldn't work in the REPL, only where the function is defined in a .clj file on the classpath. 虽然这在REPL中不起作用,但只能在类路径上的.clj文件中定义函数。 Which doesn't answer your question, then: you'd need to have a
defn
that stores, in the metadata of the fn
it defines, the source of the function. 那么你的问题没有回答:你需要有一个
defn
,它在它定义的fn
的元数据中存储函数的来源。 Then you'd write a function that recalls that bit of metadata. 然后你会编写一个函数来回忆那些元数据。 That shouldn't be terribly difficult.
这应该不是非常困难。
Clojure doesn't have a decompiler, so that means there's no way to get at the source of an arbitrary function unless it was a defn loaded from disk. Clojure没有反编译器,所以这意味着没有办法获得任意函数的源,除非它是从磁盘加载的defn。 However, you can use a neat hack called serializable-fn to create a function that has its source form stored in its metadata: http://github.com/Seajure/serializable-fn
但是,您可以使用名为serializable-fn的简洁hack来创建一个将源代码存储在其元数据中的函数: http : //github.com/Seajure/serializable-fn
The defsource answer is very similar to this, but this solution works with arbitrary fns, not just top-level defns. defsource答案与此非常相似,但此解决方案适用于任意fns,而不仅仅是顶级定义。 It also makes fns print prettily at the repl without a special printing function.
它还使fns在repl上打印得漂亮,没有特殊的打印功能。
In clojure 1.2's REPL, the source
function is immediately available. 在clojure 1.2的REPL中,
source
函数立即可用。 You can use it this way: 你可以这样使用它:
$ java -cp clojure.jar clojure.main Clojure 1.2.0 user=>(source slurp) (defn slurp "Reads the file named by f using the encoding enc into a string and returns it." {:added "1.0"} ([f & opts] (let [opts (normalize-slurp-opts opts) sb (StringBuilder.)] (with-open [#^java.io.Reader r (apply jio/reader f opts)] (loop [c (.read r)] (if (neg? c) (str sb) (do (.append sb (char c)) (recur (.read r))))))))) nil user=>
A few other functions are also automatically imported into the REPL's user
namespace from the clojure.repl library. 其他一些函数也会自动从clojure.repl库导入REPL的
user
命名空间。 See the API doc here . 请在此处查看API文档。
However, as pointed out in other answers here, you can't use source
as is to print back functions you have defined in the REPL. 但是,正如在此处的其他答案中所指出的,您不能使用
source
来打印您在REPL中定义的函数。
I asked exactly this question on the Clojure mailing list recently and the answers included overriding parts of the REPL to stash the input (and output) away for future reference as well as an override of defn to store the source in metadata (which you could then easily retrieve in the REPL). 我最近在Clojure邮件列表上确切地问了这个问题,答案包括覆盖REPL的部分以隐藏输入(和输出)以备将来参考,以及覆盖defn以将源存储在元数据中(然后你可以在REPL中轻松检索)。
Read the thread on the Clojure mailing list 阅读Clojure邮件列表中的主题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.