2015-07-10 117 views
5

我试图在他的2015年斯坦福大学讲座中实施Andreas Noack的草图后的GF类型,但我在早期遇到了一些问题。我使用的朱莉娅0.3.10朱利亚参数构造函数 - 外部构造函数的问题

他相关的代码如下:

# Scalar finite fields 
immutable GF{P,T<:Integer} <: Number 
    data::T 
    function GF(x::Integer) 
     return new(mod(x, P)) 
    end 
end 

    # methods for scalar finite field 
import Base: convert, inv, one, promote_rule, show, zero 

function call{P}(::Type{GF{P}}, x::Integer) 
    if !isprime(P) 
     throw(ArgumentError("P must be a prime")) 
    end 
    return GF{P,typeof(x)}(mod(x, P)) 
end 
convert{P,T}(::Type{GF{P,T}}, x::Integer) = GF{P}(x) 
convert{P}(::Type{GF{P}}, x::Integer) = GF{P}(x) 
convert{P,T}(::Type{GF{P,T}}, x::GF{P}) = GF{P,T}(x.data) 
promote_rule{P,T1,T2<:Integer}(::Type{GF{P,T1}}, ::Type{T2}) = GF{P,promote_type(T1,T2 
)} 
show(io::IO, x::GF) = show(io, x.data) 

当您尝试,只是像这样定义

GF{2}(11) 

东西,你得到

所以出现的问题

类型不能构造

好的,所以没有自动构造函数。

GF{2,Int64}(11)工作正常。

问题是没有自动构造函数的其他函数(如zero(x))失败。

企图使外部构造没有工作对我来说:

我觉得GF{P}(x::Integer) = GF{P,Int64}(x)应该工作,但我得到

警告:静态参数P不签名在发生了GF在[4]:1。 该方法将不可调用。

基本上我跑出来的想法,如何指定像 GF打电话{3}(X)应建立GF的实例{3中的typeof(X)}(x)的

我知道我错过了一些非常明显的东西。

谢谢

回答

5

不幸的是,这是根本不可能在0.3上。过载call的能力是0.4中可用的新功能之一。此功能需要调用一个不完全参数化的类型,如GF{2}。看起来Andreas在这个演示中使用了0.4-dev的版本;如果你想直接关注他的演示,我建议你也这样做。


更多细节及变通办法:

在0.3,您只需致电呼叫类型为类型的内部构造 - 但它必须是具体的(或[叶])类型。这意味着如果它有类型参数,它必须完全参数化。在这种情况下,这意味着您需要手动指定整数类型才能调用内部构造函数:GF{2,Int}(5)

您也可以定义外部构造函数,它看起来和行为就像恰好具有相同基本名称的泛型函数一样。您也可以将类型参数添加到泛型函数中,但是当它们看起来类似于某个类型的参数时(特别是当名称相同时),它们的行为会非常不同!函数的参数定义了一个局部变量,用于匹配参数的类型。这就是为什么你的定义GF{P}(x::Integer) = GF{P,Int64}(x)正在抛出这个警告:因为你从不使用P来定义参数类型,所以Julia将无法弄清楚P应该是什么,所以它永远不会被调用。我们可以创建一个函数,它总是让GF{2}

julia> GF2{T}(x::T) = GF{2,T}(x) # Call the fully parameterized inner constructor 
GF2 (generic function with 1 method) 

julia> GF2(3) 
GF{2,Int64}(1) 

请注意,我没有指定T应该是什么,当我叫GF2 - 朱莉娅想通了这一点。当你为参数化类型定义一个外部构造函数时,这会让你感到困惑,因为GF{P}(x::Integer) = …就是这个重叠点,函数参数和类型参数看起来是一样的!函数参数会胜出,所以虽然您可以使用参数定义外部构造函数,但这些参数意味着不同的内容,您可以在没有它们的情况下调用外部构造函数:GF(…)。您可以调用内部构造函数,但是您必须指定所有参数:GF{2, Int}(…)。 0.3中没有中间地带。

这个变化在0.4:现在你可以定义当你调用一个任意对象时会发生什么!这就是function call{P}(::Type{GF{P}}, x::Integer)的定义:如果您拨打不完整类型GF{2},那么将使用P=2调用此方法。事实上,这会扩展外部构造函数。一个外部构造函数(即使它被参数化)仅仅是一个“糖”,用于为​​定义GF而不带任何参数。所以这就是0.4如何通过调用超载来实现各种优秀的行为。


如果你真的想在0.3这个工作,你既可以定义功能,如GF2高于硬编码P值,或者你可以做的类型不太灵活:

immutable GF{P} <: Number 
    data::Int 
    function GF(x::Integer) 
     return new(mod(convert(Int, x), P)) 
    end 
end 

现在内部构造函数正是你想要的:GF{P},所以你可以直接调用GF{2}(5)。但是你已经失去了正在使用的整数类型的灵活性。还有其他的技巧,但那是另一次。

+0

很多感谢,这是巨大的帮助,移动到开发分支似乎是要走的路... – Robin

+0

@Robin如果你觉得这个(优秀)答复回答你的问题,那么请通过点击勾号标记回应并考虑投票。干杯。 –