只需几处更改即可定义新方法

Mat*_*hew 5 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[i]
     ...
   end
   ...
end
Run Code Online (Sandbox Code Playgroud)

此解决方案复制代码,因此使程序更难维护.我可以拆分...成两个函数调用的不同辅助函数,但结果代码很难遵循

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

function f(a, w::Union(Nothing, Vector) = nothing)
   ....
   for x in a
      ...
      s += (w == nothing)? x[i] : x[i] * w[i]
      ...
   end
   ....
end
Run Code Online (Sandbox Code Playgroud)

与第一个版本相比,此代码需要检查循环中每个步骤的条件,这听起来效率不高.

我确信有更好的解决方案,可能使用宏.处理这个问题的好方法是什么?

Mat*_* B. 4

有很多方法可以完成这类事情,从可选参数到自定义类型,再到使用@evaled 代码生成进行元编程(当您循环遍历可能性列表时,这将拼接每个新方法的更改)。

\n\n

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

\n\n

定义自定义数组类型非常简单ones

\n\n
immutable Ones{N} <: AbstractArray{Int,N}\n    dims::NTuple{N, Int}\nend\nBase.size(O::Ones) = O.dims\nBase.getindex(O::Ones, I::Int...) = (checkbounds(O, I...); 1)\n
Run Code Online (Sandbox Code Playgroud)\n\n

我选择使用 anInt作为元素类型,因为它往往会得到很好的推广。现在您所需要的只是在参数列表中更加灵活一点,然后就可以开始了:

\n\n
function f(a::Vector, w::AbstractVector=Ones(size(a))\n    \xe2\x80\xa6\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n