如何在Clojure中实现Racket的define-values宏?
Clojure实现类似Racket define-values的全局多变量绑定
你的宏之所以会绑定到自动生成的符号,是因为用了b#这种带#的自动生成符号(gensym),def b#相当于定义了一个系统自动命名的全局变量,而非你传入的目标符号。
先修复单个变量的定义宏
如果只是想实现单个全局变量的自定义绑定,正确的宏应该直接引用传入的符号:
(defmacro defvar [sym val] `(def ~sym ~val)) ;; 调用测试 (defvar 'a 2) (println a) ; => 2
实现多变量全局绑定(类似Racket的define-values)
要一次性将多个全局变量绑定到对应的值,我们可以写一个def-values宏,通过解构表达式返回的序列,逐个定义全局变量:
(defmacro def-values [syms expr] `(let [~syms ~expr] ~@(map (fn [sym] `(def ~sym ~sym)) syms))) ;; 基础调用示例 (def-values [a b c] [1 2 3]) (println a) ; => 1 (println b) ; => 2 (println c) ; => 3 ;; 支持返回序列的表达式 (def-values [x y] ((fn [] [(+ 5 3) (* 4 2)]))) (println x) ; => 8 (println y) ; => 8
这个宏的逻辑很直接:
- 先用
let把表达式返回的序列解构到目标符号列表中; - 再逐个将这些符号定义为全局变量,值就是
let里已经绑定好的对应值。
Clojure没有Racket的values函数直接返回多值,但可以用向量、列表等序列类型传递多值,宏会自动完成解构。
内容的提问来源于stack exchange,提问作者user324885
相关产品推荐
相关产品推荐

