调用宏后出现问题:
@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类型的对象不可调用”。但是,如果我用x-> x * x替换:( body)得到了预期的结果,那么我的目标就是推广宏调用。
答案 0 :(得分:3)
我通常发现使用宏中的表达式更容易(这不是编写事物的最短方法,但是根据我的经验,控制生成的内容要容易得多)。
因此,我将您的代码重写为:
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
现在您可以写:
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
请记住,我介绍的方法不是完美且通用的-只是举一个非常简单的示例,说明您如何做到这一点。