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