如何改写Clojure宏使其输出原始代码并正确显示序列结果?
解决方案
针对你的两个问题,我们可以通过以下方式修改宏:
核心修改点
- 保留原始代码结构:原宏使用
'~form会在宏展开时求值form并quote结果,导致代码被展开。改为在宏展开阶段用pr-str直接获取form的结构字符串,避免不必要的展开。 - 正确显示序列结果:原宏直接用
str转换结果,lazy seq这类对象会输出内存地址。改为用pr-str序列化结果,确保集合、序列以可读形式展示。 - 移除冗余函数:原
symbol-several函数将字符串拼接为symbol无实际意义,改为直接输出内容。
修改后的代码
(defn clean-code-str "移除代码字符串中的clojure.core命名空间前缀,贴近手写形式" [s] (clojure.string/replace s #"clojure\.core/" "")) (defmacro ! [& forms] `(do ~@(for [form forms] `(let [result# ~form] (println (str ~(clean-code-str (pr-str form)) " ;-> " (pr-str result#))) result#))))
效果验证
- 执行
(! (map inc [1 2 3])),输出:(map inc [1 2 3]) ;-> (2 3 4) - 执行
(! (do (def v [3 4]) (def l '(1 2))(0 ~@l ~@v)))`,输出:(do (def v [3 4]) (def l '(1 2)) (seq (concat (list '0) l v))) ;-> (0 1 2 3 4)
注:由于Clojure reader会提前解析反引号(`)和unquote(~)语法,宏无法完全还原原始输入的反引号写法,但已避免将unquote的结果直接展开为具体值,保留了代码的结构逻辑。
内容的提问来源于stack exchange,提问作者Nikolay Kudinov
相关产品推荐
相关产品推荐

