我已经把我的更大的问题减少到一个人工的MVE (最小可行的例子)使用文件-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")))文本文件中的“你好”。
现在,我想创建协议的另一个实现,这次是通过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"))文本文件中的“你好”。文本文件中的“你好”。
在我的实际问题中,我在协议中有许多功能,其中一个实现只是以所示的方式包装另一个。注意,在包装器实现中,方法名dump被复制。让我们用宏消除该复制(当真正的协议有许多方法时,值得这样做):
(defmacro wrap-path-string [method]
`(~method [path-str] (-> path-str, io/file, ~method)))
(extend-type java.lang.String
Dumper
(wrap-path-string dump))噢,编译器不喜欢它:
此类型不支持线程"main“中的异常:符号,编译:(wrapper_mve/core.clj:18:1)在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’处理宏调用(在苹果酒中很难在这里复制),它看起来不错。我不知道如何进行更深入的调试,但也许这里的人能发现问题所在。
同样,我知道这个MVE有更好的解决方案,使用文件-io API,但我真的想调试宏,而不是想办法避免使用它,因为我需要包装-宏策略在我的实际问题。
发布于 2016-10-01 18:25:27
我认为问题在于,extend-type本身就是一个宏,宏扩展从最外层的形式开始(而不是函数计算,它在调用函数之前对每个参数进行评估)。在这种情况下,extend-type的宏展开试图将表单(wrap-path-string dump)看作函数体,并期望第二个条目是arg向量,但找到符号dump。
如果您想要走这条路,我认为您需要编写一个宏,该宏将生成所需的expand-type表单,并且所有函数体都已经展开。
https://stackoverflow.com/questions/39809055
复制相似问题