2016-10-01 62 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是正确答案的情况。 –