2015-01-21 13 views
5

In Julia möchte ich den Typ eines Funktionsarguments als Array von Arrays angeben. So habe ichWie kann ich einen Typ für ein Funktionsargument angeben, ohne seine Dimensionen zu beschränken?

function foo{T <: Any}(x::Array{Array{T}}) 

aber wenn ich das Argument x im REPL, zum Beispiel:

x = Array[[0,1],[1,2,3],[0,1,2,4]] 

dann automatisch es wird die folgende Typzuweisung (zum Beispiel), das seine Dimensionen umfasst:

x::Array{Array{T,N},1} 

, so dass ich den Fehler

ERROR: `foo` has no method matching foo(::Array{Array{T,N},1}). 

Ich möchte nicht auf alle Array-Dimensionen beschränken, so dachte, dass die Lösung vielleicht etwas entlang der Linien von

function foo{T <: Any, N <: Number}(x::Array{Array{T,N},N}) 

aber das funktioniert auch nicht.

Wie kann ich den Argumenttyp als Array von Arrays angeben?

+3

Können Sie ein Beispiel hinzufügen, wie Sie etwas wie Ihr 'x' erzeugen? Meine Ahnung ist, dass Sie auf [Invarianz] (http://docs.julaulang.org/en/release-0.3/manual/types/?highlight=invariant#parametric-composite-types) stoßen, und dass eine Definition wie 'foo {T <: Array} (x :: Array {T})' wird den Trick machen. –

+0

Ja, das funktioniert, war ich nicht sicher über die Regeln für das Setzen des '' '{T <: Array}' '' Bit. Zum Beispiel, wenn ich mehr als ein Argument mit dem gleichen Problem hatte, wie kann ich hineinlegen mehrere Typparameter? Danke für den Link, es war sehr hilfreich, ich war mir nicht sicher, wo ich vorher hinschauen sollte. Ich habe ein Beispiel hinzugefügt, wie ich '' 'x''' zu der Frage erzeuge. – StephUnna

Antwort

7

Gegeben ein Array von Arrays x = Array[isodd(i) ? [1i,2i] : [1.0i 2.0i] for i=1:10], berichtet Julia seinen Typ als Array{Array{T,N},1}. Dies täuscht, denn es scheint zu implizieren, dass es einige T und einige N gibt, für die der obige Typ passt. Aber das ist nicht der Fall: die ungeraden Elemente werden vom Typ Array{Int,1} sein, und die Evens sind Array{Float64,2}. Also, wenn Sie versuchen, eine Methode für foo mit den Typparameter zu schreiben:

foo{T,N}(::Array{Array{T,N},1}) = T,N 

Was für x sind T und N? Natürlich gibt es kein solches N - es ist sowohl 1 und 2! Und die Elemente dieser Subarrays sind nicht vom Typ Any - sie sind sowohlInt und Float64. Dasselbe gilt für Array[[0,1],[0,1,2]], obwohl in Ihrem Beispiel Sie wissen, dass T und N konsistent sind, Julia's Typsystem nicht ... und Sie könnten möglicherweise Elemente, die keine Int-Vektoren sind, verschieben.

Es gibt eine Reihe von Möglichkeiten. Der beste Ansatz besteht darin, sicherzustellen, dass Ihre Arrays immer konkrete (oder zumindest einheitliche) Elementtypen haben, aber das ist nicht immer möglich. Wenn Sie Ihr Beispiel x oben angeben, können Sie stattdessen schreiben: x = Array{Int,1}[[0,1],[1,2,3],[0,1,2,4]].

Eine weitere Alternative ist Ihre Funktion Signatur zu ändern:

foo{N}(x::Array{Array,N}) = 1 # Will *only* work for arrays like x above 
foo{T<:Array, N}(x::Array{T,N} = 2 # Will work for all arrays of arrays 

Die erste wird nur anwendbar, wenn Sie genau diese Art zu invariance aufgrund haben, während die zweite für alle Arrays von Arrays arbeiten, die beide schlecht getippt und Beton.

(Edit: Als abschließende Bemerkung, N<:Number wird wörtliche Zahlen nicht übereinstimmen Es wird Typen übereinstimmen, ein Subtyp von Number sind, wie Real oder Int..Es gibt derzeit keine Möglichkeit auszudrücken, dass ein Typparameter ein Wert vom Typ Int sein muss, der über die Konvention hinausgeht, dass N eine ganze Zahl ist.