如何缩短函数体中的类型

时间:2016-08-17 19:31:12

标签: julia

最好通过一个例子来解释:

我定义了一个类型

type myType
    α::Float64
    β::Float64
end
z = myType( 1., 2. )

然后假设我想将此类型作为参数传递给函数:

myFunc( x::Vector{Float64}, m::myType ) =
    x[1].^m.α+x[2].^m.β

有没有办法传递myType,以便我可以以“更干净”的方式在函数体中实际使用它,如下所示:

    x[1].^α+x[2].^β

感谢您的回答。

3 个答案:

答案 0 :(得分:7)

一种方法是将调度用于更通用的功能:

myFunc( x::Vector{Float64}, α::Float64, β::Float64) = x[1].^α+x[2].^β
myFunc( x::Vector{Float64}, m::myType = myFunc(x,m.α,m.β)

或者如果您的功能较长,您可能需要使用Parameters.jl的@unpack

function myFunc( x::Vector{Float64}, m::myType )
  @unpack m: α,β #now those are defined
  x[1].^α+x[2].^β
end

解压缩的开销很小,因为你没有复制,它只是做了一堆α=m.α而只是使α指向m.α。对于较长的方程式,如果你有很多字段并在长时间计算中使用它们,这可能是一个更好的形式(作为参考,我在DifferentialEquations.jl中经常使用它。)

修改

评论中提到了另一种方式。让我说明一下。您可以使用Parameters.jl中的@with_kw宏来定义类型(使用可选的kwargs)。例如:

using Parameters
@with_kw type myType
  α::Float64 = 1.0 # Give a default value
  β::Float64 = 2.0 
end
z = myType() # Generate with the default values

然后您可以使用由@unpack_myType宏自动生成的@with_kw宏:

function myFunc( x::Vector{Float64}, m::myType )
  @unpack_myType m
  x[1].^α+x[2].^β
end

同样,这只会产生无需复制的参考α和β的开销,所以它非常轻量级。

答案 1 :(得分:1)

您可以将其添加到您的函数正文中:

(α::Float64, β::Float64) = (m.α, m.β)

答案 2 :(得分:1)

更新:我的原始答案出于一个微妙的原因是错误的,但我认为这是一个非常有趣的信息,所以不要完全删除它,我会留下一个解释为什么这是不对的。非常感谢凤阳指出全球范围内的评价! (以及在Expr上下文中使用$!)

原始答案提出:

[eval( parse( string( i,"=",getfield( m,i)))) for i in fieldnames( m)]

将返回具有赋值副作用的列表推导,因为它在概念上会产生类似[α=1., β=2., etc]的内容。假设这项任务将在当地范围内。但是,正如所指出的那样,eval始终在全局范围内进行评估,因此上述单行内容并不符合其意图。例如:

julia> type MyType
         α::Float64
         β::Float64
       end

julia> function myFunc!(x::Vector{Float64}, m::MyType)
         α=5.; β=6.; 
         [eval( parse( string( i,"=",getfield( m,i)))) for i in fieldnames( m)]
         x[1] = α; x[2] = β; return x
       end;

julia> myFunc!([0.,0.],MyType(1., 2.))
2-element Array{Float64,1}:
 5.0
 6.0

julia> whos()
                        MyType    124 bytes  DataType
                        myFunc      0 bytes  #myFunc
                             α      8 bytes  Float64
                             β      8 bytes  Float64

即。正如你所看到的,意图是局部变量α和β被覆盖,但它们没有; eval将α和β变量放在全局范围内。作为一名matlab程序员,我天真地认为eval()在概念上等同于Matlab,没有实际检查。事实证明它更像evalin('base',...)命令。

再次感谢Fengyand提供另一个例子,说明为什么短语“parse and eval”似乎与Julia程序员在the knights who until recently said "NI"上的单词“it”具有相同的效果。 :)