【发布时间】:2016-10-01 16:40:25
【问题描述】:
我已将更大的问题简化为人工 MVE(最小可行示例) 使用 file-io 进行说明。我的问题涉及某个包装宏 我在下面解释;它不涉及使用 file-io API 的更好方法; 我只是用file-io小而简单地说明宏问题 语境。我真正的问题中的包装宏策略更难展示和 解释一下,但这个 MVE 抓住了问题的要点。
考虑以下协议:
(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'ing 宏调用(在 CIDER 中,
在这里很难复制),看起来还不错。我不知道如何调试
更深,但也许这里有人可以发现问题。
再次,我知道这个 MVE 有更好的文件 io API 解决方案,但我真的 想调试宏,而不是想办法避免使用它,因为我需要 我真正的问题中的包装宏策略。
【问题讨论】:
-
在野外遇到过这样的代码,并且自己编写了一些代码,我强烈建议您手动编写函数,即使这意味着重复自己。如果您必须在几年后重新访问代码,将来您会感谢您不必解压缩嵌套的宏层。