2014-04-27 4 views
11

Julia style guide говорит следующее:Julia: Массивы с абстрактными параметрами вызывают ошибки, но переменные с абстрактными типами не

Не используйте ненужные статические параметры. Функция подпись:

foo{T<:Real}(x::T) = ... 

должен быть записан как:

foo(x::Real) = ... 

Я ожидал, что обратиться к параметрам массива тоже. Однако, если я пишу следующий код:

ret1(x::Real) = x 
ret2(x::Array{Float64,2}) = x 
ret3(x::Array{Real,2}) = x 
ret1(1.0) 
ret2(rand(2,2)) 
ret3(rand(2,2)) 

тогда я получаю следующий вывод на консоль (с помощью Джулию 0.2.1):

MethodError(ret3,(
2x2 Array{Float64,2}: 
0.841121 0.322133 
0.469432 0.495438,)) 

Так почему же Джулия выдаст ошибку для массивов с абстрактным типом параметры, но не для переменных с абстрактными типами?

ответ

9

В случае ret3, параметр типа фактически необходимо, потому что тип, который никогда не может быть построена параметры типа Джулии инвариантны. Это немного тонкая тема, но ключевым фактом является то, что в то время как Float64 <: Real истинно, Array{Float64} <: Array{Real} is не. Сначала это немного запутывает, но это необходимо для того, чтобы компилятор мог знать макет памяти аргументов функции при создании кода. Дополнительную информацию см. На странице manual.

Таким образом, вы можете направить на Real как в ret1, потому что, когда вы передаете ему Float64, Float64 <: Real правда, в то время как в ret3 вы передаете его Array{Float64} и Array{Float64} <: Array{Real} это не так, значит, ошибка нет метода. Чтобы исправить это, используйте параметр типа:

julia> ret3{T <: Real}(x::Array{T,2}) = x 
ret3 (generic function with 2 methods) 

julia> ret3(rand(2,2)) 
2x2 Array{Float64,2}: 
0.0857132 0.353194 
0.802737 0.717292 
+0

Да, я думал, что будет ответ. Но тогда это требует статических параметров, которые в противном случае казались бы ненужными. Почему у Джулии нет типа массива, который обеспечивает, чтобы все элементы были одного типа? – user664303

+0

Я несколько смущен, Джулия бесконечное количество типов массивов, которые обеспечивают, чтобы все элементы были одного и того же типа: 'Array {Float64}', 'Array {String}' и т. Д. И т. Д. Вы имеете в виду что-то, что принуждает элементы одного типа, не указывая, какой тип? –

+0

Я предлагаю тип массива, такой как ArrayHomogenous {T}, где T может быть абстрактным типом, таким как Real или Number, но для которого компилятор знает, что каждый элемент будет одного и того же типа, независимо от того, какой тип может быть. – user664303

2

В случае ret3, строго Array{Real, 2} ожидается, то есть массив, который может содержать любой вид Real переменных внутри (в то время как rand(2,2) является массивом Float64 только).

В этом случае статический параметр не является ненужным:

ret3{T<:Real}(x::Array{T,2}) = x