Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 将参数传递到语法引用的宏中_Clojure_Macros - Fatal编程技术网

Clojure 将参数传递到语法引用的宏中

Clojure 将参数传递到语法引用的宏中,clojure,macros,Clojure,Macros,在我们的clojure模块中查找一个bug时,我偶然发现了一个引用语法的宏,有人向它传递了参数。经过一些调试后,我意识到这并没有达到预期的效果,因为参数没有应有的值 下面是实际代码中遇到的情况的最低限度的表示。它应该很好地说明这一点: (def testargs {:arg1 "foo" :arg2 "bar"}) (defmacro argtest [arg1 arg2] `(str ~@(arg1 testargs) " " ~@(arg2 testa

在我们的clojure模块中查找一个bug时,我偶然发现了一个引用语法的宏,有人向它传递了参数。经过一些调试后,我意识到这并没有达到预期的效果,因为参数没有应有的值

下面是实际代码中遇到的情况的最低限度的表示。它应该很好地说明这一点:

(def testargs {:arg1 "foo"
               :arg2 "bar"})

(defmacro argtest
  [arg1 arg2]
  `(str ~@(arg1 testargs) " " ~@(arg2 testargs))
如果我像下面这样调用代码,这会很好地工作:

(argtest :arg1 :arg2)
=> "foo bar"
(defmacro argtest
  [arg1 arg2]
  `(str (~arg1 ~testargs) " " (~arg2 ~testargs)))
但是,如果将这两个参数作为变量传入,则其效果不太好:

(let [arg1 :arg1 arg2 :arg2]
  (argtest arg1 arg2))
=> " "
为了弄清问题的根源,我对宏进行了如下更改,然后再次运行测试:

(defmacro argtest2
  [arg1 arg2]
  (str arg1 " " arg2))

(argtest2 :arg1 :arg2)
=> ":arg1 :arg2"

(let [argument1 :arg1 argument2 :arg2]
  (argtest2 argument1 argument2))
=> "argument1 argument2"
如您所见,所发生的是变量名作为值传递。我怎样才能避免这种情况?我应该试着重写代码以避免宏,还是我可以以某种方式使其工作

一个显而易见的解决方案当然是这样的:

(argtest :arg1 :arg2)
=> "foo bar"
(defmacro argtest
  [arg1 arg2]
  `(str (~arg1 ~testargs) " " (~arg2 ~testargs)))

但是,由于宏的输出在求值之前插入到另一个代码块中,这是不可能的。

表单在传递到宏之前不会像传递函数一样求值。在没有更广泛的背景或不知道您要做什么的情况下,最简单的解决方案是使用函数,因为您似乎希望在所有情况下都对参数进行求值,尽管我可能过于简化了您的问题:

(defn argtest [arg1 arg2]
  (str (arg1 testargs) " " (arg2 testargs)))

表单在传递给宏之前不会像与函数一样进行求值。在没有更广泛的背景或不知道您要做什么的情况下,最简单的解决方案是使用函数,因为您似乎希望在所有情况下都对参数进行求值,尽管我可能过于简化了您的问题:

(defn argtest [arg1 arg2]
  (str (arg1 testargs) " " (arg2 testargs)))

~testargs
->
testargs
应该可以正常工作?(1)如果可以将宏更改为函数,请执行此操作。(2) 如果没有,请按cfrick所说的做,使用
~
而不是
~@
,这在您的演示中似乎是不必要的。@cfrick:是的,我在这里发布的内容也适用,但生成的代码稍后会插入到线程宏中,这会开始大量抛出异常…@Alan Thompson:谢谢,我选择了(1)。似乎有些人确实有点太喜欢他们的宏了。
~testargs
->
testargs
应该可以正常工作?(1)如果可以将宏更改为函数,那么就这样做。(2) 如果没有,请按cfrick所说的做,使用
~
而不是
~@
,这在您的演示中似乎是不必要的。@cfrick:是的,我在这里发布的内容也适用,但生成的代码稍后会插入到线程宏中,这会开始大量抛出异常…@Alan Thompson:谢谢,我选择了(1)。似乎有些人确实有点太喜欢他们的宏了。如果我编写原始代码,我会选择这种方法,但作者选择使用宏来使用存储在映射中的引用列表生成代码,并将生成的代码插入到线程宏中。。。现在,我已经花了大约6个小时试图解决这个混乱局面,按照这里的建议,在不到一个小时的时间里,用一个简单的函数图取代了整个问题。谢谢大家!如果我编写原始代码,我会选择这种方法,但作者选择使用宏来使用存储在映射中的引用列表生成代码,并将生成的代码插入到线程宏中。。。现在,我已经花了大约6个小时试图解决这个混乱局面,按照这里的建议,在不到一个小时的时间里,用一个简单的函数图取代了整个问题。谢谢大家!