您偶然发现了 @formula language,它在 StatsModels.jl 包中定义,并在 Julia 生态系统中的许多与统计/计量经济学相关的包中实现。
正如你所说,@formula 是一个宏,它将赋予它的表达式(此处为 y ~ x1 + x2)转换为其他一些 Julia 表达式。如果您想了解在 Julia 中调用宏时会发生什么——我承认这对新用户(有时是有经验的用户)来说通常看起来很神奇——@macroexpand 宏可以帮助你。在这种情况下:
julia> @macroexpand @formula(y ~ x1 + x2)
:(StatsModels.Term(:y) ~ StatsModels.Term(:x1) + StatsModels.Term(:x2))
上面的结果是@formula宏构造的表达式。我们看到公式宏中的变量被转换为StatsModels.Term 对象。如果我们直接使用StatsModels,我们可以自己构造这个:
julia> Term(:y) ~ Term(:x1) + Term(:x2)
FormulaTerm
Response:
y(unknown)
Predictors:
x1(unknown)
x2(unknown)
julia> (Term(:y) ~ Term(:x1) + Term(:x2)) == @formula(y ~ x1 + x2)
true
现在~ 是怎么回事,正如你所说,它可以用于 Julia 中的否定?这里发生的事情是StatsModels 为~ 定义了方法(在 Julia 和infix operator 中,这意味着它本质上是一个可以在其参数之间写入的函数,而不必使用其参数调用括号内:
julia> (Term(:y) ~ Term(:x)) == ~(Term(:y), Term(:x))
true
所以写y::Term ~ x::Term和调用~(y::Term, x::Term)是一样的,而这种调用~的方法是用StatsModels定义的(见下面的方法6):
julia> methods(~)
# 6 methods for generic function "~":
[1] ~(x::BigInt) in Base.GMP at gmp.jl:542
[2] ~(::Missing) in Base at missing.jl:100
[3] ~(x::Bool) in Base at bool.jl:39
[4] ~(x::Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8}) in Base at int.jl:254
[5] ~(n::Integer) in Base at int.jl:138
[6] ~(lhs::Union{AbstractTerm, Tuple{Vararg{AbstractTerm,N}} where N}, rhs::Union{AbstractTerm, Tuple{Vararg{AbstractTerm,N}} where N}) in StatsModels at /home/nils/.julia/packages/StatsModels/pMxlJ/src/terms.jl:397
请注意,您还可以在此处找到一般否定的含义(上面的方法 3,它定义了在布尔参数上调用 ~ 的行为,并且在 Base Julia 中)。
我同意 GLM.jl 文档可能不是世界上最全面的文档,但其中一个原因是 @formula 背后的整个机制实际上不是 GLM.jl 的东西 - 所以这样做查看上面链接的 StatsModels 文档,我认为这些文档非常好。