2017-09-22 5 views
3

v06 Ich möchte eine Signatur schreiben, die 2 bis 3 Argumente erwartet. Der erste ist entweder ein Integer oder Vektor von Integer. Die zweite ist entweder ein Vektor von Integer oder Matrix von Integer. Der dritte ist entweder ein Vektor von Integer oder nicht angegeben.Julia scheitert an Mehrfachversand

Ich versuchte es zuerst wie diese

function foo(
a::Union{Integer, Vector{Integer}}, 
b::Union{Vector{Integer}, Matrix{Integer}}, 
c::Union{Void, Vector{Integer}} = nothing) 

Als ich das nennen wie diese foo(3, [0o7, 0o5]) Ich erhalte einen Fehler mir zu sagen, dass es passend ist nicht in der Lage.

ERROR: LoadError: MethodError: no method matching foo(::Int64, ::Array{UInt8,1}) 
Closest candidates are: 
    foo(::Union{Array{Integer,1}, Integer}, !Matched::Union{Array{Integer,1}, Array{Integer,2}}) at ... 
    foo(::Union{Array{Integer,1}, Integer}, !Matched::Union{Array{Integer,1}, Array{Integer,2}}, !Matched::Union{Array{Integer,1}, Void}) at ... 

Jetzt verstehe ich, warum julia nicht in der Lage ist, diese Array{UInt8} <: Array{Integer} == false zu passen, aber dies scheint einfach nicht von julia, intelligent zu sein.

Dann habe ich versucht, diese

foo(a::Union{Z1, Vector{Z1}}, 
    b::Union{Vector{Z2}, Matrix{Z2}}, 
    c::Union{Void, Vector{Z3}} = nothing 
    ) where {Z1 <: Integer, Z2 <: Integer, Z3 <: Integer} 

Jetzt julia auch mir nicht sagen, was passt nicht!

ERROR: LoadError: MethodError: no method matching foo(::Int64, ::Array{UInt8,1}, ::Void) 
Closest candidates are: 
    foo(::Union{Array{Z1<:Integer,1}, Z1<:Integer}, ::Union{Array{Z2<:Integer,1}, Array{Z2<:Integer,2}}, ::Union{Array{Z3<:Integer,1}, Void}) where {Z1<:Integer, Z2<:Integer, Z3<:Integer} at ... 
    foo(::Union{Array{Z1<:Integer,1}, Z1<:Integer}, ::Union{Array{Z2<:Integer,1}, Array{Z2<:Integer,2}}) where {Z1<:Integer, Z2<:Integer} at ... 
+0

Wenn Sie sehr komplizierte Typ-Signaturen wie diese haben, insbesondere mit vielen Unionen, kann es ein Zeichen dafür sein, dass Sie sie in mehrere separate Methodendefinitionen aufteilen sollten. Insbesondere möchten Sie wahrscheinlich das 'foo (a, b, c = nichts)' zugunsten von 'foo (a, b, c)' und 'foo (a, b)' vermeiden. Überlegen Sie auch, ob es eine Verbindung zwischen den Typen gibt, zum Beispiel ist 'a' ein' Vektor' nur, wenn 'b' eine' Matrix' ist? – DNF

+0

@DNF Ich verstehe Ihre Bedenken. Das Problem ist, dass, wenn ich das tue, der Benutzer nutzlose julia Fehlermeldungen anstelle der nützlichen bekommt, die ich schreibe. Z.B. "Es gibt keine Methode, wo Sie eine Matrix für b haben und c ist Leere", ich habe es eher so "Wenn Sie b als Matrix angeben, müssen Sie c als Vektor mit diesen Dimensionen angeben". Tatsächlich ist diese Signatur die Bullshit-Check-Signatur, die die echte Methode aufruft, nachdem sie alles überprüft und alles auf den richtigen Typ geworfen hat. – Nozdrum

+0

Sie stellen sich auf eine Menge expliziter Eingabe-Checks ein, was der Idee des multiplen Versands widerspricht. Sie verursachen sich viel Schmerz, nur um zu vermeiden, dass Menschen gewöhnlichen Julia-Fehlermeldungen ausgesetzt werden. Außerdem würde ich überrascht sein, dass "c" "Leere" ist, wenn ich überhaupt kein "c" liefern würde! Vorschlag: Teilen Sie Ihre Funktion in separate Methoden mit korrekten Signaturen auf. Dann machen Sie eine Fallback-Methode (oder mehrere), die den Rest abfängt: 'f (a, b, c) = ...' ohne Typen, und lassen Sie das herauszufinden, was mit den Eingaben falsch ist und Fehler ausgibt. – DNF

Antwort

6

Ja, Array{UInt8} <: Array{Integer} == false. Dies wird "parametrische Invarianz" genannt. Viele andere Fragen haben dieses Thema diskutiert.

Das andere Problem, das Sie in laufen lassen, obwohl, ist, dass wenn Sie einen statische Funktion Parameter - das heißt, f(…) where T - das TMuss Spiel etwas, da es für den Einsatz in dem Körper der Funktion zur Verfügung steht. Dies führt zu Problemen in Union s, wobei T nicht in jeder Option verfügbar ist. Ich glaube, dass es ein offenes Problem gibt, dieses Verhalten zu ändern, um übereinstimmende Union Elemente zuzulassen, die T nicht enthalten, die diese Bindung in eine undefinierte Variable verwandeln würden, wenn Sie versuchten, darauf zuzugreifen.

Die Problemumgehung im Moment besteht darin, den Typ vars zu verwenden, der nicht statische Parameter der Funktion sind. Beispiel:

+0

IIRC, in alten Tagen, als Dreiecksversand nicht unterstützt wurde, müssen wir eine "Typaliase" definieren, um diese zu umgehen, z. 'typalias IntVector {T <: Ganzzahl} Vektor {T}', 'foo (x :: Union {Ganzzahl, IntVektor}) = x'. Freut mich zu sehen, dass das nicht mehr benötigt wird! – Gnimuc

Verwandte Themen