朱莉娅:宏如何知道它们的参数何时停止?
Julia: How do macros know when their arguments stop?
这是一个初学者问题,但我在文档(或 Whosebug 上)中找到答案时遇到了一些问题,我认为它对其他人也有帮助。问题很简单:
Julia 宏调用如何知道宏的参数何时完成?
用括号标明论点时,应该直截了当(我觉得……)。然而,在另一种情况下,它似乎更微妙。我怀疑它与“表达式数量”有关(这本身可能是一个有点棘手的概念)但我不确定并且我想拥有记录在案的官方规则。
为什么我认为这不明显的一些例子:
julia> macro a(arg...)
print(arg)
end;
julia> @a gg=3 if true # the :(gg = 3) is the first argument of the macro
print("val")
a = 1;;; # the macro does not see the semicolons (which makes sense to me)
end # the if statement is the second argument of the macro
# note: replacing "true" by "@a true" makes the number of arguments of
# the second macro depend on the following newline being there or not
# next: the first two assignments are two arguments. The last assignment is not an argument at all
julia> @a a = 4 f=3; aaa = "asdf"
julia> @a af = 4 (f=3; aaa = "asdf") # two arguments; the second one is a quote block
julia> @a af = 4; (f=3; aaa = "asdf") # one argument.
# edit:
julia> @a @a aa # One argument, counterexample to last claim
(:(#= REPL[37]:1 =# @a aa),)
例如,是否可以将两个连续的 if 块作为单独的参数?
我似乎注意到的一条规则是(当不使用圆括号括起参数时)如果宏部分 (@a
) 被删除,任何具有多个参数的宏调用将变为无效语法。一般来说是这样吗?
编辑:
否,请参阅代码段中的反例。
规则:
@name expr1 expr2 ...
宏调用是一个宏,提供所有白色 space 分隔表达式,直到到达语句末尾。通常,当您到达换行符、;
或其他一些字符(如 ]
或 )
表示语句结束时,语句结束。
以下是一些使用 @a
宏的示例。
julia> @a @a aa # here @a aa produces one expression which is passed to outer @a call
(:(#= REPL[37]:1 =# @a aa),)
julia> @a x = 1 y = 2 # two expressions are passed to a macro
(:(x = 1), :(y = 2))
julia> @a x = 1 y = 2; # the same, but we terminated the statement using ;
(:(x = 1), :(y = 2))
julia> @a x = 1 y = 2; 1; # 1 does not go into the macro as ; terminated the statement
(:(x = 1), :(y = 2))
julia> @a (@a x) y # outer @a gets two expressions as we delimited the @a x with parentheses
(:(#= REPL[40]:1 =# @a x), :y)
julia> @a begin
@a x
end y # similar but with begin-end block
(quote
#= REPL[44]:2 =#
#= REPL[44]:2 =# @a x
end, :y)
julia> @a [@a x] y # this time we used square brackets
(:([#= REPL[39]:1 =# @a(x)]), :y)
我认为在上面的例子中,例如重要的是要看到
@a x = 1 y = 2
Julia 解析器将 x = 1
视为一个整体,尽管在 =
之间存在 space,因为它将其视为单个表达式。
另请注意,您只能将有效表达式的内容提供给宏,例如:
julia> @a =
ERROR: syntax: unexpected "="
失败为:
julia> =
ERROR: syntax: unexpected "="
(在使用 Julia 宏设计 DSL 时,这实际上是一个重要的考虑因素,因为您必须确保您设计的语法包含有效的表达式)
另请注意,宏是 all 白色 space 分隔表达式,因此这是一个错误:
julia> macro b(x)
print(x)
end
@b (macro with 1 method)
julia> @b 1 2
ERROR: LoadError: MethodError: no method matching @b(::LineNumberNode, ::Module, ::Int64, ::Int64)
最后注意:
julia> @a [@a x] y
(:([#= REPL[64]:1 =# @a(x)]), :y)
julia> @a[@a x] y
ERROR: syntax: extra token "y" after end of expression
因为 Julia 在 @a
之后以一种特殊的方式解析带有 [
的宏调用,在这种情况下仅将一个参数传递给宏。
这是一个初学者问题,但我在文档(或 Whosebug 上)中找到答案时遇到了一些问题,我认为它对其他人也有帮助。问题很简单:
Julia 宏调用如何知道宏的参数何时完成?
用括号标明论点时,应该直截了当(我觉得……)。然而,在另一种情况下,它似乎更微妙。我怀疑它与“表达式数量”有关(这本身可能是一个有点棘手的概念)但我不确定并且我想拥有记录在案的官方规则。
为什么我认为这不明显的一些例子:
julia> macro a(arg...)
print(arg)
end;
julia> @a gg=3 if true # the :(gg = 3) is the first argument of the macro
print("val")
a = 1;;; # the macro does not see the semicolons (which makes sense to me)
end # the if statement is the second argument of the macro
# note: replacing "true" by "@a true" makes the number of arguments of
# the second macro depend on the following newline being there or not
# next: the first two assignments are two arguments. The last assignment is not an argument at all
julia> @a a = 4 f=3; aaa = "asdf"
julia> @a af = 4 (f=3; aaa = "asdf") # two arguments; the second one is a quote block
julia> @a af = 4; (f=3; aaa = "asdf") # one argument.
# edit:
julia> @a @a aa # One argument, counterexample to last claim
(:(#= REPL[37]:1 =# @a aa),)
例如,是否可以将两个连续的 if 块作为单独的参数?
我似乎注意到的一条规则是(当不使用圆括号括起参数时)如果宏部分 (@a
) 被删除,任何具有多个参数的宏调用将变为无效语法。一般来说是这样吗?
编辑: 否,请参阅代码段中的反例。
规则:
@name expr1 expr2 ...
宏调用是一个宏,提供所有白色 space 分隔表达式,直到到达语句末尾。通常,当您到达换行符、;
或其他一些字符(如 ]
或 )
表示语句结束时,语句结束。
以下是一些使用 @a
宏的示例。
julia> @a @a aa # here @a aa produces one expression which is passed to outer @a call
(:(#= REPL[37]:1 =# @a aa),)
julia> @a x = 1 y = 2 # two expressions are passed to a macro
(:(x = 1), :(y = 2))
julia> @a x = 1 y = 2; # the same, but we terminated the statement using ;
(:(x = 1), :(y = 2))
julia> @a x = 1 y = 2; 1; # 1 does not go into the macro as ; terminated the statement
(:(x = 1), :(y = 2))
julia> @a (@a x) y # outer @a gets two expressions as we delimited the @a x with parentheses
(:(#= REPL[40]:1 =# @a x), :y)
julia> @a begin
@a x
end y # similar but with begin-end block
(quote
#= REPL[44]:2 =#
#= REPL[44]:2 =# @a x
end, :y)
julia> @a [@a x] y # this time we used square brackets
(:([#= REPL[39]:1 =# @a(x)]), :y)
我认为在上面的例子中,例如重要的是要看到
@a x = 1 y = 2
Julia 解析器将 x = 1
视为一个整体,尽管在 =
之间存在 space,因为它将其视为单个表达式。
另请注意,您只能将有效表达式的内容提供给宏,例如:
julia> @a =
ERROR: syntax: unexpected "="
失败为:
julia> =
ERROR: syntax: unexpected "="
(在使用 Julia 宏设计 DSL 时,这实际上是一个重要的考虑因素,因为您必须确保您设计的语法包含有效的表达式)
另请注意,宏是 all 白色 space 分隔表达式,因此这是一个错误:
julia> macro b(x)
print(x)
end
@b (macro with 1 method)
julia> @b 1 2
ERROR: LoadError: MethodError: no method matching @b(::LineNumberNode, ::Module, ::Int64, ::Int64)
最后注意:
julia> @a [@a x] y
(:([#= REPL[64]:1 =# @a(x)]), :y)
julia> @a[@a x] y
ERROR: syntax: extra token "y" after end of expression
因为 Julia 在 @a
之后以一种特殊的方式解析带有 [
的宏调用,在这种情况下仅将一个参数传递给宏。