代码之家  ›  专栏  ›  技术社区  ›  Tim Visher

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

  •  33
  • Tim Visher  · 技术社区  · 14 年前

    例如,给定:

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

    (print-definition foo)
    

    然后沿着

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

    印刷的。

    5 回复  |  直到 14 年前
        1
  •  22
  •   Mike Spross Alex Martelli    14 年前

    替代品 source clojure.repl/source 启动REPL时,如 1.2.0 . 如果你和 1.1.0 或更低, 来源 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) :

    (macroexpand '#'reduce)
    ;; => (var reduce)
    
        2
  •  18
  •   Isaac    14 年前

    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

        3
  •  14
  •   user61051 user61051    14 年前

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

    defsource的答案与此非常相似,但此解决方案适用于任意fn,而不仅仅是顶级defn。它也使fns在repl处打印美观,无需特殊的打印功能。

        4
  •  11
  •   Arthur Edelstein    14 年前

    在clojure1.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=>

    其他一些函数也会自动导入REPL的 user here .

    来源

        5
  •  4
  •   Sean Corfield    14 年前

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

    Read the thread on the Clojure mailing list