2016-10-01 57 views
0

我已經將我的更大的問題減少爲使用file-io進行說明的人爲MVE(最小可行示例) 。我的問題涉及我在下面解釋的某個封裝宏 ;它不涉及更好的方式來使用file-io API; 我只是使用file-io來說明在一個小而簡單的 上下文中的宏觀問題。我的真實問題中的包裝宏觀策略很難顯示,並且解釋了這個問題,但是這個MVE抓住了問題的要點。Clojure中的擴展類型的包裝宏策略失敗

考慮以下方案:

(defprotocol Dumper 
    (dump [this])) 

及以上java.io.File

(extend-type java.io.File 
    Dumper 
    (dump [file] 
    (with-open [rdr (io/reader file)] 
     (doseq [line (line-seq rdr)] 
     (println line))))) 

的實現,我們已經做了(:use [clojure.java.io :as io])得到reader 功能。我可以按如下方式使用這樣的:

(defn -main 
    [& args] 
    (dump (io/file "resources/a_file.txt"))) 
Hello from a text file. 

現在,我想創建該協議的另一種實現方式,這次在 java.lang.String。此實現包裝字符串,將其視爲 文件路徑字符串;創建一個clojure.java.io/file;隨後調用其他 執行議定書:

(extend-type java.lang.String 
    Dumper 
    (dump [path-str] (-> path-str, io/file, dump))) 

,並調用它像這樣:

(defn -main 
    [& args] 
    (dump (io/file "resources/a_file.txt")) 
    (dump   "resources/a_file.txt")) 
Hello from a text file. 
Hello from a text file. 

在我的真正的問題,我已經在協議中的許多功能,並且一個 實現只是以所示的方式包裝另一個。請注意,在 包裝器實現中,方法名稱dump已被複制。讓我們消除 是複製了宏(這是值得做的事情時,真正的協議有許多 方法):

(defmacro wrap-path-string [method] 
    `(~method [path-str] (-> path-str, io/file, ~method))) 

(extend-type java.lang.String 
    Dumper 
    (wrap-path-string dump)) 

哎呀,編譯器不喜歡它:

Exception in thread "main" java.lang.UnsupportedOperationException: 
    nth not supported on this type: Symbol, compiling:(wrapper_mve/core.clj:18:1) 
at clojure.lang.Compiler.analyze(Compiler.java:6688) 
at clojure.lang.Compiler.analyze(Compiler.java:6625) 
at clojure.lang.Compiler$MapExpr.parse(Compiler.java:3072) 

我嘗試了macroexpand-all'ing和macroexpand-1'宏調用(在CIDER中, 難以在此複製),並且它看起來沒問題。我不知道如何更深入地調試 ,但也許這裏有人能夠發現問題。

同樣,我知道這MVE已與文件IO的API更好的解決方案,但我真的 要調試的宏,沒有辦法避免使用它,因爲我需要 包裝宏觀策略在我的真實問題。

+1

遇到過這樣的代碼,並且自己寫了一些代碼,我會敦促你用手寫出這些函數,即使它意味着重複你自己。如果你必須在幾年後重新訪問代碼,將來你會感謝你不必拆開嵌套層的宏。 – Alex

回答

1

我認爲問題在於extend-type本身就是一個宏,宏擴展以最外層的形式開始(與函數評估相反,它在調用函數之前評估每個參數)。在這種情況下,extend-type的宏展開嘗試將(wrap-path-string dump)作爲函數體處理,並期望第二個項目是arg向量,但找到了符號dump

如果你想走這條路,我認爲你需要編寫一個宏,這個宏將生成所需的expand-type表單,其中所有已經擴展的函數體。

+0

我很懷疑。感謝您的確認。你的建議也很好。這可能是非DRY是正確答案的情況。 –