Юлия Методеррор для функциональности стиля eltype - PullRequest
3 голосов
/ 27 января 2020

У меня есть абстрактный контейнер AbstractContainer, параметризованный по типу T, который указывает тип того, что находится в контейнере. Каждый подтип (в данном случае FloatContainer) затем указывает, что на самом деле находится в контейнере (в данном случае Float64).

В идеале у меня будет возможность получить обратно, какой тип находится в контейнере, если У меня есть только тип контейнера. Таким образом, я мог бы использовать его в другой структуре (в этом примере MultiplyBy)

Я думал сделать это аналогично внутренней функции eltype Джулии, но я не могу заставить ее работать. Я всегда получаю ошибку метода (подробное сообщение об ошибке см. В последнем фрагменте)

abstract type AbstractContainer{T} end


gettype(::Type{AbstractContainer{T}}) where T = T

struct FloatContainer <: AbstractContainer{Float64}
  x::Float64
end


struct MultiplyBy{T<:AbstractContainer}
  x::gettype(T)
end


function process(m::MultiplyBy, v::AbstractContainer)
  return typeof(v)(m.x*v.x)
end


function main()
  x = FloatContainer(2.0)

  y = FloatContainer(3.0)
  op = MultiplyBy{FloatContainer}(y)

  z = process(op, x)
  println(z.x)
end


main()
ERROR: LoadError: MethodError: no method matching gettype(::TypeVar)
Closest candidates are:
  gettype(!Matched::Type{AbstractContainer{T}}) where T at /Users/.../test.jl:6

Я должен признать, что я совсем новичок в Джулии, но мне очень интересно узнать об этом больше , Так что любые советы приветствуются - либо о том, как решить эту проблему по-другому, либо где моя ошибка.

Ответы [ 2 ]

3 голосов
/ 27 января 2020

Определение типа элемента

Ваш gettype не работает, поскольку он отправляет абстрактные типы, но все ваши объекты-контейнеры будут иметь конкретные типы. Для правильной отправки необходимо использовать оператор подтипа .

Сравнить отправку по абстрактным типам:

julia> eltype1(::Type{AbstractContainer{T}}) where T = T
eltype1 (generic function with 1 method)

julia> eltype1(FloatContainer)
ERROR: MethodError: no method matching eltype1(::Type{FloatContainer})
Closest candidates are:
  eltype1(::Type{AbstractContainer{T}}) where T at REPL[4]:1
Stacktrace:
 [1] top-level scope at REPL[5]:1

julia> eltype1(AbstractContainer{Float64})
Float64

с отправкой по подтипам абстрактных типов:

julia> eltype2(::Type{<:AbstractContainer{T}}) where T = T
eltype2 (generic function with 1 method)

julia> eltype2(FloatContainer)
Float64

julia> eltype2(AbstractContainer{Float64})
Float64

Предпочитать переменные отправки явным eltype вызовам

Вызов eltype напрямую обычно не требуется; Вы можете сделать явным тип параметра c во время отправки.

В этом решении используются только типы параметров c:

julia> struct Container{T}
           x::T
       end

julia> struct MultiplyBy{T}
           x::T
       end

julia> MulitplyBy(x::Container{T}) where T = MultiplyBy{T}(x.x)
MulitplyBy (generic function with 1 method)

julia> process(m::MultiplyBy, x::Container{T}) where T = Container{T}(m.x * x.x)
process (generic function with 1 method)

julia> a = Container(2.0)
Container{Float64}(2.0)

julia> b = Container(3.0)
Container{Float64}(3.0)

julia> op = MulitplyBy(b)
MultiplyBy{Float64}(3.0)

julia> process(op, a)
Container{Float64}(6.0)
0 голосов
/ 27 января 2020

Я не уверен, что вам нужно, но я написал рабочий пример с вашей структурой:

abstract type AbstractContainer{T} end

#not necessary anymore
#gettype(a::Type{AbstractContainer{T}})  where T = T

struct FloatContainer{T<:AbstractFloat} <: AbstractContainer{T} #AbstractFloat, to include Float32, BigFloats and others
  x::T
end

 #you can't use functions on struct definitions, if you need more restrictions,
 #use a Constructor
struct MultiplyBy{T<:AbstractContainer}
  x::T
end

#example external Constructor

MultiplyBy(x::AbstractFloat) = MultiplyBy(FloatContainer(x))

value(x::AbstractContainer) = x.x #basic accesor function
value(x::MultiplyBy) = value(x.x) 

function process(m::MultiplyBy, v::AbstractContainer)
  return typeof(v)(value(m)*value(v)) #calling accesor functions to access the values.
end

function main()
  x = FloatContainer(2.0)

  y = FloatContainer(3.0)
  op = MultiplyBy(y) #the parametric type is inferred automatically, no need to use Curly Braces

  z = process(op, x)
  println(value(x)) #better use accesor functions that direct access, as the underlying implementation can change
end

main()
...