我正在尋找能夠讓REPL打印當前函數的定義。有沒有辦法做到這一點?如何在REPL中顯示Clojure中函數的定義?
例如,給定:
(defn foo [] (if true "true"))
我想這樣說
(print-definition foo)
相處的
(foo [] (if true "true"))
印刷線的東西。
我正在尋找能夠讓REPL打印當前函數的定義。有沒有辦法做到這一點?如何在REPL中顯示Clojure中函數的定義?
例如,給定:
(defn foo [] (if true "true"))
我想這樣說
(print-definition foo)
相處的
(foo [] (if true "true"))
印刷線的東西。
到source
替代(這應該開始REPL時,作爲1.2.0
通過clojure.repl/source
是可用的。如果你有1.1.0
或更低的工作,source
是clojure.contrib.repl-utils
),用於REPL使用,而不是看功能
(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 [email protected])
(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)
#'
處於.clj
文件中定義只是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郵件列表上問了這個問題,答案包括覆蓋REPL的一部分,以便將輸入(和輸出)存儲起來供將來參考,以及覆蓋defn以將源存儲在元數據中然後您可以在REPL中輕鬆檢索)。
-1,如果你在這裏包含更詳盡的解釋,這個答案可能會更好,參見[meta](http://meta.stackexchange.com/a/8259/180500)。這個答案並不真正提供具體的處方。 – 2013-11-19 19:07:58
用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=>
一些其他的功能也自動導入到REPL的從clojure.repl庫user
命名空間。請參閱API文檔here。
但是,正如其他答案中所指出的那樣,您不能按原樣使用source
來打印您在REPL中定義的函數。
Clojure中沒有一個反編譯器,這樣就意味着沒有辦法在任意函數的源代碼來獲得,除非它是從磁盤加載的DEFN。但是,您可以使用名爲serializable-fn的整潔hack創建一個將其源代碼存儲在其元數據中的函數:http://github.com/Seajure/serializable-fn
defsource的答案與此非常相似,但此解決方案適用於任意fns,而不僅僅是頂級防禦。它也使fns在repl上打印出精美,沒有特殊的打印功能。
最好放棄頭來擺脫defsource關鍵字。 (alter-meta!(var〜fn-name)assoc:source(drop 1(quote〜&form)) – haijin 2013-02-16 22:28:00