繁体   English   中英

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

[英]How can I display the definition of a function in Clojure at the REPL?

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

例如,给定:

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

我想说点什么

(print-definition foo)

并得到一些东西

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

打印。

source的替代方法(在启动REPL时应该通过clojure.repl/source ,从1.2.0 。如果你使用的是1.1.0或更低版本,则sourceclojure.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)

#'只是一个读者宏 ,从#'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的简洁hack来创建一个将源代码存储在其元数据中的函数: http//github.com/Seajure/serializable-fn

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

在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文档。

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

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

阅读Clojure邮件列表中的主题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM