Type definition: expected UnionAll, got TypeVar

匿名 (未验证) 提交于 2019-12-03 00:59:01

问题:

In the Julia manual for v0.6 I find the following:

abstract type Pointy{T} end struct Point{T} <: Pointy{T}     x::T     y::T end 

This works fine, and I thought the following should as well:

abstract type Foo{V, F} end struct Bar{V, F} <: Foo{V, F}     x::V{F} end 

The definition of Bar gives, however, the following error

ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar 

What is wrong, and how can I achieve what I really want, namely to specify that V<:AbstractVector and F<:AbstractFloat?

回答1:

Try this:

julia> abstract type Foo{T} end  julia> struct Bar{T<:AbstractFloat,V<:AbstractVector{T}} <: Foo{T}            x::V        end  julia> Bar{T}(v::AbstractVector{T}) = Bar{T,typeof(v)}(v) # constructor Bar  julia> Bar(rand(3)) Bar{Float64,Array{Float64,1}}([0.387467, 0.535419, 0.240748])  julia> Bar(rand(Int, 3)) ERROR: TypeError: Bar: in T, expected T<:AbstractFloat, got Type{Int64} Stacktrace:  [1] Bar(::Array{Int64,1}) at ./REPL[4]:1 


回答2:

Another option (got it to work concurrently with @tholy's answer and uses the same route of having V "include" the parameter F). To get it to work nicely, an external constructor should be added, like @tholy's answer (maybe this was a bit redundant, but it uses the where syntax)

struct Bar{V, F} <: Foo{V,F}     x::V     Bar{V,F}(x::V) where {F, V<:AbstractVector{F}} = new(x) end 

and this works like so:

julia> Bar{Vector{Int},Int}([1,2,3]) Bar{Array{Int64,1},Int64}([1, 2, 3])  julia> Bar{Vector{Int},Float64}([1,2,3]) ERROR: MethodError: Cannot `convert` an object of type Array{Int64,1} to an object of type Bar{Array{Int64,1},Float64} This may have arisen from a call to the constructor Bar{Array{Int64,1},Float64}(...), since type constructors fall back to convert methods. 


回答3:

Based on the answers of @tholy and @DanGetz I messed about a bit and came up with an answer I liked:

abstract type Foo{V} end struct Bar{V <: AbstractVector{<:AbstractFloat}} <: Foo{V}     x::V end  julia> Bar(rand(5)) Bar{Array{Float64,1}}([0.722314, 0.159418, 0.13561, 0.288794, 0.347009])  julia> Bar(2.0:5.0) Bar{StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}}(2.0:1.0:5.0)  julia> Bar(2:5) ERROR: MethodError: Cannot `convert` an object of type UnitRange{Int64} to an object of type Bar 

I like this because it seems simpler, the default constructor works directly, and I don't get "doubling" of the floating point typevar, that is, Bar{Array{Float64,1}} instead of Bar{Float64,Array{Float64,1}}.

Not sure if there are any drawbacks to this version, though. Also, I still don't understand why some of my efforts work and some fail with syntax or other errors.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!