我已经将我的更大的问题减少为使用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更好的解决方案,但我真的 要调试的宏,没有办法避免使用它,因为我需要 包装宏观策略在我的真实问题。
遇到过这样的代码,并且自己写了一些代码,我会敦促你用手写出这些函数,即使它意味着重复你自己。如果你必须在几年后重新访问代码,将来你会感谢你不必拆开嵌套层的宏。 – Alex