我正在尝试根据Andreas Noack在2015年斯坦福大学演讲中的草图来实现GF类型,但是在早期就有一些问题。我正在使用Julia 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)
应该可以,但是我明白了
警告:在In [4]:1处,GF的签名中未出现静态参数P。该方法将不可调用。
基本上,我对于如何指定像GF {3}(x)这样的调用应创建GF {3,typeof(x)}(x)实例的想法不多了
我知道我缺少明显的东西。
谢谢
不幸的是,这在0.3上根本不可能。过载能力call
是0.4中将提供的一项重大新功能。调用不完全参数化的类型(如)需要此功能GF{2}
。看起来Andreas在此演示中使用的是0.4开发版本。如果您想直接观看他的演示,我建议您也这样做。
更多详细信息和解决方法:
在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
。实际上,这可以概括外部构造函数。外部构造函数(即使已将其参数化)只是用于定义call(::Type{GF}, x::Integer)
类型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)
直接调用。但是您在使用的整数类型上失去了灵活性。也有其他技巧,但这是另外一次。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句