如何在REPL中显示Clojure中函数的定义?

时间:2010-09-23 22:29:37

标签: clojure

我正在寻找能够让REPL打印出函数的当前定义的能力。有没有办法做到这一点?

例如,给定:

(defn foo [] (if true "true"))

我想说点什么

(print-definition foo)

并获得

的内容
(foo [] (if true "true"))

打印。

5 个答案:

答案 0 :(得分:20)

source的替代方法(自clojure.repl/source起启用REPL时应通过1.2.0提供。)如果您使用的是1.1.0或更低,{ {1}}位于source。)中,供REPL使用,而不是查看clojure.contrib.repl-utils文件中定义的函数:

.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)

答案 1 :(得分:18)

您需要导入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的元数据中存储函数的来源。然后你会编写一个函数来回忆那些元数据。这应该不是非常困难。

答案 2 :(得分:13)

Clojure没有反编译器,所以这意味着没有办法获取任意函数的来源,除非它是从磁盘加载的defn。但是,您可以使用名为serializable-fn的简洁hack来创建一个将源表单存储在其元数据中的函数:http://github.com/Seajure/serializable-fn

defsource答案与此非常相似,但此解决方案适用于任意fns,而不仅仅是顶级定义。它还使fns在repl上打印得漂亮,没有特殊的打印功能。

答案 3 :(得分: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=>

其他一些函数也会自动从clojure.repl库导入REPL的user命名空间。请参阅API文档here

但是,正如在此处的其他答案中指出的那样,您不能使用source来打印您在REPL中定义的函数。

答案 4 :(得分:4)

我最近在Clojure邮件列表上确切地问了这个问题,答案包括覆盖REPL的部分以隐藏输入(和输出)以备将来参考,以及覆盖defn以将源存储在元数据中(然后你可以在REPL中轻松检索。

Read the thread on the Clojure mailing list