Julia 定义一个只需少量更改的新方法

Julia 定义一个只需少量更改的新方法,julia,Julia,我想写一个接受补充论点的版本。与初始版本的区别只存在于几行代码中,可能在循环中。一个典型的例子是使用权重向量w 一种解决方案是完全重写一个新函数 function f(Vector::a) ... for x in a ... s += x[i] ... end ... end function f(a::Vector, w::Vector) ... for x in a ... s += x[i]

我想写一个接受补充论点的版本。与初始版本的区别只存在于几行代码中,可能在循环中。一个典型的例子是使用权重向量
w

一种解决方案是完全重写一个新函数

function f(Vector::a)
   ...
   for x in a
      ...
      s += x[i]
      ... 
   end
   ...
end

function f(a::Vector, w::Vector)
   ... 
   for x in a
     ...
     s += x[i] * w[i]
     ...
   end
   ...
end
此解决方案复制代码,因此使程序更难维护。 我可以将
拆分为不同的助手函数,这两个函数都会调用,但生成的代码很难理解

另一种解决方案是只编写一个函数并使用
?:应更改的每行的结构

function f(a, w::Union(Nothing, Vector) = nothing)
   ....
   for x in a
      ...
      s += (w == nothing)? x[i] : x[i] * w[i]
      ...
   end
   ....
end
这段代码需要在循环的每一步检查一个条件,与第一个版本相比,这听起来效率不高

我相信有更好的解决方案,也许是使用宏。处理这个问题的好方法是什么?

在这种情况下,使用可能会起到关键作用


只需将
w
参数默认为
ones()

我已经多次遇到这个问题。如果要避免循环中的条件If语句,一种可能是对某些伪类型使用多个分派。例如:

abstract MyFuncTypes

type FuncWithNoWeight <: MyFuncTypes; end
evaluate(x::Vector, i::Int, ::FuncWithNoWeight) = x[i]

type FuncWithWeight{T} <: MyFuncTypes
    w::Vector{T}
end
evaluate(x::Vector, i::Int, wT::FuncWithWeight) = x[i] * wT.w[i]


function f(a, w::MyFuncTypes=FuncWithNoWeight())
    ....
    for x in a
        ...
        s += evaluate(x, i, w)
        ...
    end
    ....
end
抽象类型

类型FuncWithNoWeight有很多方法可以做这类事情,从可选参数到自定义类型,再到使用
@eval
'生成代码的元编程(这将在循环一系列可能性时加入每个新方法的更改)

我认为在这种情况下,我会结合使用@ColinTBowers和@GnimucKey建议的方法

定义一个自定义数组类型非常简单,它都是
one

immutable Ones{N} <: AbstractArray{Int,N}
    dims::NTuple{N, Int}
end
Base.size(O::Ones) = O.dims
Base.getindex(O::Ones, I::Int...) = (checkbounds(O, I...); 1)

这应该比其他建议的解决方案具有更低的开销
getindex
应该作为边界检查和数字
1
很好地内联,没有类型不稳定性,并且不需要重写算法。如果您确定所有访问都在边界内,您甚至可以将边界检查作为额外的优化删除。或者在最近的0.4上,您可以定义并使用
Base.unsafe_getindex(O::Ones,I::Int…)=1
(这在0.3上不太有效,因为不能保证为所有抽象数组定义它)。

您可以在循环开始之前进行检查,并将结果设置为布尔变量。谢谢。但是假设
x[i]
是一个int,而
x[i]w[i]
是一个float。这不会导致类型不稳定吗?在上面的代码中,dummyType仍然是类型不稳定的。虽然我不认为它会导致很多分配,但它会阻止evaluate直接内联到for循环中,我认为Julia会在每次调用它时查找分派(尽管我们知道它没有改变)。最好将不同类型的选择移到默认参数中,这样函数体中的类型总是相同的。@MattB。啊,谢谢你。我没有注意到这种代码模式会引入类型不稳定性,但我现在可以看到。我已经更新了我的答案。现在去更新我自己的代码中我犯了这个错误的地方:-)代码有一个问题。您需要将FuncWithWeight参数化为eltype为w。否则,函数f不是专门用于
w
的eltype(我试图编辑您的答案,但未被接受)。@Matthew同意。事实上,在查看LLVM IR时,我非常确定乘法是常数折叠的。因此,这里唯一的开销是
checkbounds
——这是可以删除的。
function f(a::Vector, w::AbstractVector=Ones(size(a))
    …