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
Macros 混淆clojure宏var评估_Macros_Clojure - Fatal编程技术网

Macros 混淆clojure宏var评估

Macros 混淆clojure宏var评估,macros,clojure,Macros,Clojure,我试图编写一个clojure宏,将clojure关键字转换为java枚举。但宏中参数的计算令人困惑: user=> (defmacro show-and-tell [thing] #_=> `(vector ~(name thing) ~(type thing) ~thing)) #'user/show-and-tell user=> (macroexpand-1 (show-and-tell :foo)) ["foo" clojure.lang.Keyword :foo]

我试图编写一个clojure宏,将clojure关键字转换为java枚举。但宏中参数的计算令人困惑:

user=> (defmacro show-and-tell [thing]
#_=>   `(vector ~(name thing) ~(type thing) ~thing))
#'user/show-and-tell
user=> (macroexpand-1 (show-and-tell :foo))
["foo" clojure.lang.Keyword :foo]
user=> (def foo :bar)
#'user/foo
user=> (name foo)
"bar"
user=> (type foo)
clojure.lang.Keyword
user=> (macroexpand-1 (show-and-tell foo))
["foo" clojure.lang.Symbol :bar]
因此,如果关键字直接作为参数提供,它的工作原理与我预期的一样。但是如果它是一个var,我就不能得到正确的
名称
类型

我可以通过使用eval使其“几乎”工作:

user=> (defmacro show-and-tell-with-eval [thing]
  #_=>   `(vector ~(name (eval thing)) ~(type (eval thing)) ~(eval thing)))
#'user/show-and-tell-with-eval
user=> (macroexpand-1 '(show-and-tell-with-eval foo))
(clojure.core/vector "bar" clojure.lang.Keyword :bar)
user=> (let [baz :bar-foo] (macroexpand-1 '(show-and-tell baz)))
(clojure.core/vector "baz" clojure.lang.Symbol baz)
user=> (let [baz :bar-foo] (macroexpand-1 '(show-and-tell-with-eval baz)))
CompilerException java.lang.RuntimeException: Unable to resolve symbol: baz in this context

有人能给我解释一下吗?是否无法在宏中查看(本地)变量的
名称

(defmacro show-and-tell [thing] `(vector (name ~thing) (type ~thing) ~thing))
特别解释:

理解发生了什么的关键是知道参数何时被计算。宏将未计算的数据结构作为参数,并返回一个数据结构,然后使用上述规则对其进行计算。使用
~
告诉编译器应该在运行时计算哪些数据结构,因此,
thing
参数,而不是
(name thing)
值的返回值,因为
thing
值将在编译时绑定,在后一种情况下,这不是您想要的


这里有关于编写宏的进一步说明

您可能想要编写宏

(defmacro show-and-tell [thing] `(vector (name ~thing) (type ~thing) ~thing))
特别解释:

理解发生了什么的关键是知道参数何时被计算。宏将未计算的数据结构作为参数,并返回一个数据结构,然后使用上述规则对其进行计算。使用
~
告诉编译器应该在运行时计算哪些数据结构,因此,
thing
参数,而不是
(name thing)
值的返回值,因为
thing
值将在编译时绑定,在后一种情况下,这不是您想要的


这里有关于编写宏的进一步说明

您可能想要编写宏

(defmacro show-and-tell [thing] `(vector (name ~thing) (type ~thing) ~thing))
特别解释:

理解发生了什么的关键是知道参数何时被计算。宏将未计算的数据结构作为参数,并返回一个数据结构,然后使用上述规则对其进行计算。使用
~
告诉编译器应该在运行时计算哪些数据结构,因此,
thing
参数,而不是
(name thing)
值的返回值,因为
thing
值将在编译时绑定,在后一种情况下,这不是您想要的


这里有关于编写宏的进一步说明

您可能想要编写宏

(defmacro show-and-tell [thing] `(vector (name ~thing) (type ~thing) ~thing))
特别解释:

理解发生了什么的关键是知道参数何时被计算。宏将未计算的数据结构作为参数,并返回一个数据结构,然后使用上述规则对其进行计算。使用
~
告诉编译器应该在运行时计算哪些数据结构,因此,
thing
参数,而不是
(name thing)
值的返回值,因为
thing
值将在编译时绑定,在后一种情况下,这不是您想要的


在这里,您对编写宏有了进一步的解释

您似乎对变量之间的关系、它们包含的内容以及宏是如何发挥作用感到困惑。“变量提供了一种引用可变存储位置的机制”(参见)。当您在REPL中计算
foo
时,Clojure将根据中概述的规则对其进行计算,在本例中,这意味着它将符号解析为“由符号命名的全局变量的绑定值”

现在,理解宏“是操纵形式的函数,允许语法抽象”是至关重要的。基本上,宏允许直接访问交给宏的任何参数,然后根据需要操作和计算相关数据。让我们来看看你的宏和你的“错误”的例子:

您的宏定义会被输入一些
内容
(显示和告知
的参数是什么)。此时,
问题
将无法解决。只有在宏定义中才有一些计算。请注意,在此调用中,您正在调用
macroexpand-1
,调用
(show and tell foo)
的(评估)结果,这可能不是您想要的:

user=> (macroexpand-1 (show-and-tell foo))
["foo" clojure.lang.Symbol :bar]
引用电话说明发生了什么:

user=> (macroexpand-1 '(show-and-tell foo))
(clojure.core/vector "foo" clojure.lang.Symbol foo)
您使用“foo”(即
foo
名称
)调用
vector
,其中
foo
是一个符号,然后您的代码将正常解析
foo
(并给出
:bar

从您的描述中,您似乎期望所有参数都会出现正常的符号解析。如果这是您想要的,那么您首先不需要宏。但是为了记录在案,现在你需要做的事情应该是显而易见的:你需要先评估
东西
(这与你使用
eval
所做的差不多)。换句话说,您将
unquote
运算符放错了:

(defmacro show-and-tell [thing]
  `(vector (name ~thing) (type ~thing) ~thing))
user=> (macroexpand-1 '(show-and-tell foo))
(clojure.core/vector (clojure.core/name foo) (clojure.core/type foo) foo)
user=> (show-and-tell foo)
["bar" clojure.lang.Keyword :bar]

您似乎对变量之间的关系、它们包含的内容以及宏如何发挥作用感到困惑。“变量提供了一种引用可变存储位置的机制”(参见)。当您在REPL中计算
foo
时,Clojure将根据中概述的规则对其进行计算,在本例中,这意味着它将符号解析为“由符号命名的全局变量的绑定值”

现在,理解宏“是操纵形式的函数,允许语法抽象”是至关重要的。基本上,宏允许直接访问交给宏的任何参数,然后根据需要操作和计算相关数据。让我们来看看你的宏和你的“错误”的例子:

您的宏定义会被输入一些
内容
(显示和告知
的参数是什么)。此时,
问题
将无法解决。只在你的宏定义里哟