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))

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

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

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

Ответ 1

В случае ret3 параметр типа действительно необходим, потому что a Array{Real} - тип, который никогда не может быть построен. Параметры типа Юлии являются инвариантными. Это немного тонкая тема, но ключевым фактом является то, что, хотя Float64 <: Real истинно, Array{Float64} <: Array{Real} нет. Сначала это немного запутывает, но это необходимо для того, чтобы компилятор мог знать макет памяти аргументов функции при создании кода. Подробнее см. 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

Ответ 2

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

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

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

Ответ 3

Начиная с julia 1.2, я считаю, что для ret3 необходимо набрать:

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