user =>(def v-1“这是v1”)
user =>(def v-2“这是v2”)
user =>(defmacro m [v](符号(str“ v-” v)))
user =>(m 1)
“这是v1”
user =>(m 2)
“这是v2”
user =>(让[i 2](m i))
CompilerException java.lang.RuntimeException:无法解析符号:v-i在这种情况下,编译:(NO_SOURCE_PATH:73:12)
我可以同时写一个宏吗
(m 2)
和
(让[i 2](m i))
获取“这是v2”?
答案 0 :(得分:6)
没有宏,这是可能的:
(defn m [v] (var-get (resolve (symbol (str "v-" v)))))
(m 1) ;; => "This is v1"
(let [i 2] (m i)) ;; => "This is v2"
如果需要,您也可以使用宏:
(defmacro m [v] `@(resolve (symbol (str "v-" ~v))))
答案 1 :(得分:1)
一个普通的函数似乎更可能是您想要的。
但是,首先要解决最初的问题,如果您要坚持使用宏,宏是在编译时会被调用的常规函数,因此您可以使用其符号名称查找Var并获取其使用deref
的值,就像您在应用程序的运行时(而不是宏的运行时)那样:
(defmacro var-value [vsym] @(resolve vsym))
(def foo 1)
(var-value foo)
;= 1
(macroexpand-1 '(var-value foo))
;= 1
请注意,上面的1
是此处的实际宏扩展。这与
(defmacro var-value [vsym] `@(resolve ~vsym))
因为后者扩展为对resolve
的调用,因此将实现的查询推迟到您应用的运行时。
(macroexpand-1 '(var-value foo))
;= (clojure.core/deref (clojure.core/resolve foo))
因此,无论您在哪里调用该宏,该代码都将内联。
当然,宏也可以扩展为符号-例如。
(defmacro prefixed-var [suffix]
`(symbol (str "v-" ssuffix)))
会产生v-1
(对于(prefixed-var 1)
)等扩展名。
这里,回到宏的适用性主题,但是,如果您使用宏,则产生扩展所需的所有信息必须在编译时可用,因此通常您不能使用的值。 let
/ loop
扩展中的局部变量或函数参数的根本原因是,它们在编译时没有固定值。 1
因此,最干净的方法可能是将resolve
调用包装在defn
中并调用结果函数–尽管可以肯定地知道,我们需要知道您要尝试的问题是什么通过引入执行Var查找的宏来解决。
1 除非是静态分配的常量值(如问题文本中给出的示例所示),否则我假设您正在考虑一般使用本地语言的运行时值,而不仅仅是使用初始化表达式为常量文字的那些值。