Macros 将宏变量传递给函数进行插值
我试图编写一个宏,对表达式求值,然后将其与几个值进行比较。 对于这篇文章,我已经把这个问题简化为一个较小的例子Macros 将宏变量传递给函数进行插值,macros,julia,metaprogramming,hygiene,Macros,Julia,Metaprogramming,Hygiene,我试图编写一个宏,对表达式求值,然后将其与几个值进行比较。 对于这篇文章,我已经把这个问题简化为一个较小的例子 macro small_bad(item) quote $(use_val(esc(item))) end end function use_val(val) quote if $val == 1 1 elseif $val == 2 2 else
macro small_bad(item)
quote
$(use_val(esc(item)))
end
end
function use_val(val)
quote
if $val == 1
1
elseif $val == 2
2
else
-1
end
end
end
因为我不想多次计算expr,所以我想将它保存在一个变量中。
所以我试了一下:
macro small_good(item)
quote
begin
val = $(esc(item))
$(begin
use_val(val)
end)
end
end
end
但是我得到,val
在@small\u good
的插值中是未定义的
我还尝试传递use_val(:val)
,但这也失败了,因为宏系统将重命名
val
指向其他对象
我怎样才能做到这一点
编辑:
给出了第一个答案,我在实际代码中尝试了这一点
macro match(item, arms)
var = gensym(:var)
quote
let $var = $(esc(item))
$(begin
code = :nothing
for e in reverse(filter((e) -> e isa Expr, arms.args))
code = make_match(var, e, code)
end
code
end)
end
end
end
并得到UndefVarError:##var#253未定义
免责声明:我知道match.jl包中已经实现了@match
宏,我正在重新实现其中的一个子集作为学习练习
编辑2:
我想出来了。在使用François Févotte的建议之后,我现在不得不改变我的use_val
的真实版本,它实际上是在做$(esc(val))
,而不是$val
我的错误是没有包括那个细节。将更新要点以反映这一点如果我理解您的要求,这应该可以:
macro small(item)
var = gensym(:var)
quote
let $var = $(esc(item))
$(use_val(var))
end
end
end
function use_val(val)
quote
if $val == 1
1
elseif $val == 2
2
else
-1
end
end
end
它扩展到如下内容:
julia> using MacroTools
julia> MacroTools.@expand @small myexpr
quote
let octopus = myexpr
begin
if octopus == 1
1
elseif octopus == 2
2
else
-1
end
end
end
end
既没有卫生问题,也没有多重评估问题:
# Testing in a local scope introduced by `let`
# is a good way to check for hygiene issues
julia> let arg = [1]
@small pop!(arg)
end
1
现在我猜,在MWE创建过程中,您原始问题的许多实质内容已经丢失,因为所有这些基本上等同于:
julia> function small(val)
if val == 1
1
elseif val == 2
2
else
-1
end
end
small (generic function with 1 method)
julia> let args = [1]
small(pop!(args))
end
1
我不能完全让它工作。我会用你的建议更新这篇文章,可能会带来更相关的背景。