【问题标题】:Julia: Is it possible to transform `fn(df, @macro1 :a, :b, :c)` into `fn(df, (:a, :b, :c)...)`Julia:是否可以将 `fn(df, @macro1 :a, :b, :c)` 转换为 `fn(df, (:a, :b, :c)...)`
【发布时间】:2020-09-01 13:39:07
【问题描述】:

例如,我想写一个宏@macro1 来转换

transform(df, @macro :X :Y)

transform(df, (:X, :Y)...)

这是我的尝试

macro macro1(ex...)
    println(ex)
    :($ex...)
end

transform(df, @macro1 :X :Y)

这似乎很难。但是,如果允许宏像这样在外面

@macro transform(df, (:X :Y))

那就更容易了。但是我不确定“内部”宏样式是否可以实现这一点。

【问题讨论】:

  • 有什么意义呢?这部分是否更复杂?
  • 是的。复杂得多
  • 查看我的编辑。以前的版本只是在这个特殊的测试用例中偶然起作用:我认为你必须避免使用 varargs 变体。

标签: julia metaprogramming


【解决方案1】:

我猜你想用逗号让它工作?

julia> macro splicing(expr)
           return Expr(:(...), esc(expr))
       end
@splicing (macro with 1 method)

julia> @macroexpand tuple(:w, @splicing :x, :y)
:(tuple(:w, (:x, :y)...))

julia> tuple(:w, @splicing :x, :y)
(:w, :x, :y)

微妙之处在于语法@m a, b被解析为@m((a, b))。我们可以直接将其包装到 splice 调用中。

不要尝试使用实际的可变参数,但可能会发生令人讨厌的堆栈溢出。

对于大小为 1 的输入,您可能需要一种特殊情况,因为这不会构造元组:

julia> tuple(:w, @splicing :x)
ERROR: MethodError: no method matching iterate(::Symbol)
Closest candidates are:
  iterate(::Core.SimpleVector) at essentials.jl:600
  iterate(::Core.SimpleVector, ::Any) at essentials.jl:600
  iterate(::ExponentialBackOff) at error.jl:218
  ...
Stacktrace:
 [1] top-level scope at REPL[34]:1

以下方法可能有效,但可能会变得脆弱:

macro splicing3(expr)
    if Meta.isexpr(expr, :tuple)
        return Expr(:(...), esc(expr))
    else
        return esc(expr)
    end
end

【讨论】:

    猜你喜欢
    • 2011-05-30
    • 2021-10-31
    • 1970-01-01
    • 2017-01-05
    • 2012-09-03
    • 2014-03-23
    • 1970-01-01
    • 2021-12-27
    • 2020-07-15
    相关资源
    最近更新 更多