我正在寻找让REPL打印出函数当前定义的能力.有没有办法做到这一点?
例如,给定:
(defn foo [] (if true "true"))
Run Code Online (Sandbox Code Playgroud)
我想说点什么
(print-definition foo)
Run Code Online (Sandbox Code Playgroud)
并得到一些东西
(foo [] (if true "true"))
Run Code Online (Sandbox Code Playgroud)
打印.
May*_*iel 20
替代source(应该clojure.repl/source在启动REPL时可用,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))
Run Code Online (Sandbox Code Playgroud)
一个简单的print-definition:
(defn print-definition [v]
(:source (meta v)))
(print-definition #'foo)
Run Code Online (Sandbox Code Playgroud)
#'只是一个读者宏,从:扩展#'foo到(var foo):
(macroexpand '#'reduce)
;; => (var reduce)
Run Code Online (Sandbox Code Playgroud)
Isa*_*aac 18
您将要导入repl命名空间,并使用source它中的函数:
(ns myns
(:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)
=> (foo [] (if true "true"))
nil
Run Code Online (Sandbox Code Playgroud)
虽然这在REPL中不起作用,但只能在类路径上的.clj文件中定义函数.然而,你没有回答你的问题:你需要defn在fn它定义的元数据中存储函数的来源.然后你会编写一个函数来回忆那些元数据.这应该不是非常困难.
小智 13
Clojure没有反编译器,所以这意味着没有办法获得任意函数的源,除非它是从磁盘加载的defn.但是,您可以使用名为serializable-fn的简洁hack来创建一个将源代码存储在其元数据中的函数:http://github.com/Seajure/serializable-fn
defsource答案与此非常相似,但此解决方案适用于任意fns,而不仅仅是顶级定义.它还使fns在repl上打印得漂亮,没有特殊的打印功能.
Art*_*ein 11
在clojure 1.2的REPL中,该source功能立即可用.你可以这样使用它:
$ 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=>
其他一些函数也会自动user从clojure.repl库导入到REPL的命名空间中.请在此处查看API文档.
但是,正如在此处的其他答案中所指出的那样,您不能source按原样使用打印在REPL中定义的函数.
我最近在 Clojure 邮件列表上问了这个问题,答案包括覆盖 REPL 的部分以隐藏输入(和输出)以供将来参考,以及覆盖 defn 以将源存储在元数据中(然后您可以在 REPL 中轻松检索)。
| 归档时间: |
|
| 查看次数: |
10887 次 |
| 最近记录: |