将宏变量传递给函数进行插值

门德斯

我正在尝试编写一个对表达式求值的宏,然后将其与一些值进行比较。我已将此问题简化为一个较小的示例。

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

我的错误是没有包括该细节。将更新要点以反映这一点

弗朗索瓦·费沃特(FrancoisFévotte)

如果我了解您的需求,那么应该可以:

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章