2010-09-23 66 views

回答

19

source替代(這應該開始REPL時,作爲1.2.0通過clojure.repl/source是可用的。如果你有1.1.0或更低的工作,sourceclojure.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) 
+0

最好放棄頭來擺脫defsource關鍵字。 (alter-meta!(var〜fn-name)assoc:source(drop 1(quote〜&form)) – haijin 2013-02-16 22:28:00

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的元數據中存儲函數的來源。然後,你會寫一個函數來回憶那些元數據。這應該不是非常困難。

4

我剛剛在Clojure郵件列表上問了這個問題,答案包括覆蓋REPL的一部分,以便將輸入(和輸出)存儲起來供將來參考,以及覆蓋defn以將源存儲在元數據中然後您可以在REPL中輕鬆檢索)。

Read the thread on the Clojure mailing list

+0

-1,如果你在這裏包含更詳盡的解釋,這個答案可能會更好,參見[meta](http://meta.stackexchange.com/a/8259/180500)。這個答案並不真正提供具體的處方。 – 2013-11-19 19:07:58

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=>

一些其他的功能也自動導入到REPL的從clojure.repl庫user命名空間。請參閱API文檔here

但是,正如其他答案中所指出的那樣,您不能按原樣使用source來打印您在REPL中定義的函數。

13

Clojure中沒有一個反編譯器,這樣就意味着沒有辦法在任意函數的源代碼來獲得,除非它是從磁盤加載的DEFN。但是,您可以使用名爲serializable-fn的整潔hack創建一個將其源代碼存儲在其元數據中的函數:http://github.com/Seajure/serializable-fn

defsource的答案與此非常相似,但此解決方案適用於任意fns,而不僅僅是頂級防禦。它也使fns在repl上打印出精美,沒有特殊的打印功能。