Julia 在元编程中按顺序专门化方法调用

Julia 在元编程中按顺序专门化方法调用,julia,Julia,调用宏后出现问题: @introspectable square(x) = x * x 那么打电话的时候 广场(3) 我应该能够得到9,因为函数调用已经被专门化,以执行结构的属性,即Julia代码,但是当我进入宏时,代码似乎是直接计算的 我所尝试的: struct IntrospectableFunction name parameters native_function end (f::IntrospectableFunction)(x) = f.native_functio

调用宏后出现问题:

@introspectable square(x) = x * x
那么打电话的时候 广场(3) 我应该能够得到9,因为函数调用已经被专门化,以执行结构的属性,即Julia代码,但是当我进入宏时,代码似乎是直接计算的

我所尝试的:

struct IntrospectableFunction
  name
  parameters
  native_function
end


(f::IntrospectableFunction)(x) = f.native_function(x)

macro introspectable(expr)
  name = expr.args[1].args[1]
  parameters = tuple(expr.args[1].args[2:end]...)
  body = expr.args[2].args[2]

:( global $name  = IntrospectableFunction( :( name ), $parameters, :( body ) ))
end

@introspectable square(x) = x * x
square(3)

答案应该是9,但是我得到“类型为symbol的对象不可调用”。但是,如果我将:(body)替换为x->x*x,我会得到想要的结果,我的目标是泛化宏调用。

我通常发现在宏中使用表达式更容易(这不是编写东西的最短方法,但根据我的经验,控制生成的内容要容易得多)

因此,我将您的代码改写为:

macro introspectable(expr)
    name = expr.args[1].args[1]
    parameters = expr.args[1].args[2:end]
    anon = Expr(Symbol("->"), Expr(:tuple, parameters...), expr.args[2].args[2])
    constr = Expr(:call, :IntrospectableFunction, QuoteNode(name), Tuple(parameters), anon)
    esc(Expr(:global, Expr(Symbol("="), name, constr)))
end
现在,正如你所说,你想要一般性,我会这样定义你的函子:

(f::IntrospectableFunction)(x...) = f.native_function(x...)
(通过这种方式,您可以传递多个位置参数)

现在让我们测试一下我们的定义:

julia> @introspectable square(x) = x * x
IntrospectableFunction(:square, (:x,), getfield(Main, Symbol("##3#4"))())

julia> square(3)
9

julia> @macroexpand @introspectable square(x) = x * x
:(global square = IntrospectableFunction(:square, (:x,), ((x,)->x * x)))

julia> @introspectable toarray(x,y) = [x,y]
IntrospectableFunction(:toarray, (:x, :y), getfield(Main, Symbol("##5#6"))())

julia> toarray("a", 10)
2-element Array{Any,1}:
   "a"
 10

julia> @macroexpand @introspectable toarray(x,y) = [x,y]
:(global toarray = IntrospectableFunction(:toarray, (:x, :y), ((x, y)->[x, y])))

julia> function localscopetest()
       @introspectable globalfun(x...) = x
       end
localscopetest (generic function with 1 method)

julia> localscopetest()
IntrospectableFunction(:globalfun, (:(x...),), getfield(Main, Symbol("##9#10"))())

julia> globalfun(1,2,3,4,5)
(1, 2, 3, 4, 5)

julia> function f()
       v = 100
       @introspectable localbinding(x) = (v, x)
       end
f (generic function with 1 method)

julia> f()
IntrospectableFunction(:localbinding, (:x,), getfield(Main, Symbol("##11#12")){Int64}(100))

julia> localbinding("x")
(100, "x")
(请注意,使用
@macroexpand
可确保宏按预期工作)

编辑-如何处理最小的多次分派 我正在编写一个非宏示例,因为它与数据结构有关:

例如,使用以下定义:

struct IntrospectableFunction
  name::Symbol
  method_array::Vector{Pair{Type{<:Tuple}, Function}}
end

function (f::IntrospectableFunction)(x...)
    for m in f.method_array
        if typeof(x) <: first(m)
            return last(m)(x...)
        end
    end
    error("signature not found")
end

请记住,我提出的方法并不完美且通用-它只是提供了一个非常简单的示例,说明了如何做到这一点。

谢谢你,这确实很有帮助,也很清楚。比如说,我想重载2种方法,square(x)=x*x和square(x,y)=x*y。你会怎么做?我会在回答中进行评论,但你已经到了想在Julia中重新实现方法分派机制的地步。
julia> square = IntrospectableFunction(:square, [Tuple{Any}=>x->x*x,Tuple{Any,Any}=>(x,y)->x*y])
IntrospectableFunction(:square, Pair{DataType,Function}[Tuple{Any}=>##9#11(), Tuple{Any,Any}=>##10#12()])

julia> square(3)
9

julia> square(2,3)
6