我把我的更大问题减少为人工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
'和macroexpand-1
'宏调用(在CIDER中,
很难在这里复制),看起来还不错。我不知道如何调试
更深层次,但也许这里有人能发现问题。
同样,我知道这个MVE有更好的文件io API解决方案,但我真的 想要调试宏,没有找到避免使用它的方法,因为我需要 在我真正的问题中包装宏观策略。
答案 0 :(得分:1)
我认为问题在于extend-type
本身就是一个宏,而宏展开始于最外层的形式(而不是函数评估,它在调用函数之前评估每个参数)。在这种情况下,extend-type
的宏展开试图将形式(wrap-path-string dump)
视为函数体,并期望第二个项为arg向量,但找到符号dump
。
如果你想走这条路,我想你需要编写一个宏,它将产生所需的expand-type
形式,所有的功能体已经扩展到位。