我正在尝试编写一个对表达式求值的宏,然后将其与一些值进行比较。我已将此问题简化为一个较小的示例。
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_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 not defined
免责声明:我知道该@match
宏已经在Match.jl包中实现,我正在将其子集重新实现为学习练习
编辑2:
我想到了。使用弗朗索瓦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
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句