Почему я не могу указать тип имен в именованном кортеже как кортеж символов в Julia? - PullRequest
4 голосов
/ 30 марта 2020

Есть эта функция:

function Γ(state::Dict{Symbol, <:Tuple{Vararg{Symbol}}})::Vector{NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}}
    kwargs = Dict(kwargs)
    keys = [key for (key, value) ∈ state]
    instances_vec = [value for (key, value) ∈ state]
    data = Vector{Vector{Symbol}}()
    function recursive(data, current, depth = 1)
        if depth <= length(instances_vec)
            for instance ∈ instances_vec[depth]
                recursive(data, push!(copy(current), instance), depth + 1)
            end
        else
            push!(data, current)
        end
    end
    recursive(data, [])
    return [(;zip(keys,configuration)...) for configuration ∈ data]
end

, которая при запуске выглядит следующим образом:

identifiers = Dict(:Id=>(:One, :Two, :Three, :Four, :Five), :Nationality=>(:Brit, :German), :Color=>(:Red, :Blue, :Green))

Γ(identifiers)

выдает следующую ошибку:

ERROR: MethodError: Cannot `convert` an object of type
NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}} to an object of type
NamedTuple{#s589,#s588} where #s588<:Tuple{Vararg{Symbol,N} where N} where #s589<:Tuple{Vararg{Symbol,N} where N}

Тип возвращаемого значения is: Array{NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}},1}, а тип (:Id, :Nationality, :Color) равен Tuple{Symbol,Symbol,Symbol}, поэтому я не понимаю, почему это приводит к ошибке преобразования, когда нет необходимости в преобразовании, особенно если:

typeof((:Id, :Nationality, :Color)) <: Tuple{Vararg{Symbol}} && Tuple{Symbol,Symbol,Symbol} <: Tuple{Vararg{Symbol}} = true

1 Ответ

3 голосов
/ 30 марта 2020

Во-первых, преобразование происходит из-за того, что объявление вашей функции объявляет тип возвращаемого значения. Если вы удалите (или закомментируете) аннотацию этого типа

function Γ(state::Dict{Symbol, <:Tuple{Vararg{Symbol}}}) #::Vector{NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}}
    kwargs = Dict() # <- there was a typo here in your minimal example
    keys = [key for (key, value) ∈ state]
    instances_vec = [value for (key, value) ∈ state]
    data = Vector{Vector{Symbol}}()
    function recursive(data, current, depth = 1)
        if depth <= length(instances_vec)
            for instance ∈ instances_vec[depth]
                recursive(data, push!(copy(current), instance), depth + 1)
            end
        else
            push!(data, current)
        end
    end
    recursive(data, [])
    return [(;zip(keys,configuration)...) for configuration ∈ data]
end

, тогда все в порядке:

julia> identifiers = Dict(:Id=>(:One, :Two, :Three, :Four, :Five), :Nationality=>(:Brit, :German), :Color=>(:Red, :Blue, :Green))
Dict{Symbol,Tuple{Symbol,Symbol,Vararg{Symbol,N} where N}} with 3 entries:
  :Id          => (:One, :Two, :Three, :Four, :Five)
  :Nationality => (:Brit, :German)
  :Color       => (:Red, :Blue, :Green)

julia> Γ(identifiers)
30-element Array{NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}},1}:
 (Id = :One, Nationality = :Brit, Color = :Red)
 (Id = :One, Nationality = :Brit, Color = :Blue)
 (Id = :One, Nationality = :Brit, Color = :Green)
 [...]

Обратите внимание, что ввод аргументов функции / метода, где это необходимо, считается хорошей практикой , Тем не менее, код, который обеспечивает утверждения типа для возвращаемых значений, часто менее идиоматичен c в Джулии: компилятор действительно хорош в выяснении, что такое возвращаемый тип!

Теперь причина неудачного преобразования заключается в том, что тип элемента, указанный в сигнатуре, не соответствует фактическому типу элемента возвращаемого вектора:

julia> elem = (Id = :One, Nationality = :Brit, Color = :Red)
(Id = :One, Nationality = :Brit, Color = :Red)

julia> typeof(elem)
NamedTuple{(:Id, :Nationality, :Color),Tuple{Symbol,Symbol,Symbol}}

julia> elem isa NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}
false

Для совпадения NamedTuple{A,B} NamedTuple{<:Tuple{Vararg{Symbol}}, <:Tuple{Vararg{Symbol}}}, должны соблюдаться оба условия:

  • A <: Tuple{Vararg{Symbol}}
  • B <: Tuple{Vararg{Symbol}}

Здесь мы имеем:

A = (:Id, :Nationality, :Color)
B = Tuple{Symbol,Symbol,Symbol}

, так что, как вы сказали, выполняется условие для B:

julia> B <: Tuple{Vararg{Symbol}}
true

, но не условие для A:

julia> A <: Tuple{Vararg{Symbol}}
ERROR: TypeError: in <:, expected Type, got Tuple{Symbol,Symbol,Symbol}
Stacktrace:
 [1] top-level scope at REPL[10]:1

       # A is a value of type Tuple{...}, not the type itself
julia> typeof(A) <: Tuple{Vararg{Symbol}}
true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...