【发布时间】:2010-09-23 22:29:37
【问题描述】:
我正在寻找让 REPL 打印函数的当前定义的能力。有没有办法做到这一点?
例如,给定:
(defn foo [] (if true "true"))
我想说几句
(print-definition foo)
并得到类似的东西
(foo [] (if true "true"))
打印出来的。
【问题讨论】:
标签: clojure
我正在寻找让 REPL 打印函数的当前定义的能力。有没有办法做到这一点?
例如,给定:
(defn foo [] (if true "true"))
我想说几句
(print-definition foo)
并得到类似的东西
(foo [] (if true "true"))
打印出来的。
【问题讨论】:
标签: clojure
source 的替代方案(从1.2.0 开始,在启动 REPL 时应该可以通过clojure.repl/source 获得。如果您使用的是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))
一个简单的print-definition:
(defn print-definition [v]
(:source (meta v)))
(print-definition #'foo)
#' 只是一个reader macro,从#'foo 扩展到(var foo):
(macroexpand '#'reduce)
;; => (var reduce)
【讨论】:
您需要导入 repl 命名空间,并从中使用 source 函数:
(ns myns
(:use [clojure.repl :only (source)]))
(defn foo [] (if true "true"))
(source foo)
=> (foo [] (if true "true"))
nil
虽然这在 REPL 中不起作用,但只有在类路径上的 .clj 文件中定义函数时才起作用。那么,这不能回答您的问题:您需要有一个defn,它在它定义的fn 的元数据中存储函数的来源。然后,您将编写一个函数来调用该元数据。这应该不是很困难。
【讨论】:
Clojure 没有反编译器,这意味着除非它是从磁盘加载的 defn,否则无法获取任意函数的源代码。但是,您可以使用一种称为 serializable-fn 的巧妙技巧来创建一个将其源形式存储在其元数据中的函数:http://github.com/Seajure/serializable-fn
defsource 的答案与此非常相似,但此解决方案适用于任意 fns,而不仅仅是顶级 defns。它还使 fns 在 repl 上打印得很漂亮,而无需特殊的打印功能。
【讨论】:
在 clojure 1.2 的 REPL 中,source 函数立即可用。你可以这样使用它:
$ java -cp clojure.jar clojure.main
Clojure 1.2.0
用户=> (源 slurp)
(定义啜饮
"使用编码enc将f命名的文件读入字符串
并将其归还。”
{:添加“1.0”}
([f & opts]
(让 [opts (normalize-slurp-opts opts)
某人 (StringBuilder.)]
(with-open [#^java.io.Reader r (应用 jio/reader f opts)]
(循环 [c (.read r)]
(如果(否定?c)
(str 某人)
(做
(.append sb (char c))
(recur (.read r)))))))))
零
用户=>
其他一些函数也会从 clojure.repl 库自动导入到 REPL 的 user 命名空间中。请参阅 API 文档here。
但是,正如此处其他答案所指出的,您不能按原样使用 source 来打印您在 REPL 中定义的函数。
【讨论】:
我最近在 Clojure 邮件列表上准确地询问了这个问题,答案包括重写部分 REPL 以隐藏输入(和输出)以供将来参考,以及重写 defn 以将源存储在元数据中(其中然后您可以轻松地在 REPL 中检索)。
【讨论】: