2017-09-16 4 views
1

Ich habe keine Ahnung, warum this example mehrdeutig ist. (Ich entschuldige mich, dass ich den Code hier nicht hinzugefügt habe, es ist einfach zu lang.)Mehrdeutige Verwendung von "faul"

Ich habe prefix (_ maxLength) als Überlast zu LazyDropWhileBidirectionalCollection hinzugefügt. subscript(position) ist definiert auf LazyPrefixCollection. Dennoch sollte der folgende Code aus dem obigen Beispiel nicht mehrdeutig sein, aber es ist:

print([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2)[0]) // Ambiguous use of 'lazy' 

Es ist mein Verständnis, dass eine Überlastung, die in der Protokollhierarchie höher ist wird gewöhnen.

Nach dem Compiler kann es nicht zwischen zwei Arten wählen; nämlich LazyRandomAccessCollection und . (Was nicht sinnvoll ist, da subscript(position) keine Methode von LazySequence ist.) LazyRandomAccessCollection wäre hier die logische Wahl.

Wenn ich den Index zu entfernen, es funktioniert:

print(Array([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2))) // [0, 1] 

Was das Problem sein könnte?

+1

Der Compiler-Ausgang zeigt die zwei möglichen Kandidaten für 'faul' –

+1

Könnten Sie bitte den entsprechenden" Problemcode "posten? – shallowThought

+0

@shallowThought Der relevante Problemcode ist die letzte Zeile des Links im ersten Satz. Ich habe es dem obigen Beitrag hinzugefügt. –

Antwort

1

Der Weg hier ist einfach zu kompliziert und mehrdeutig. Sie können dies sehen, indem Sie Elemente löschen. Insbesondere den letzten Index fallen:

let z = [0, 1, 2].lazy.drop(while: {_ in false}).prefix(2) 

In dieser Konfiguration will der Compiler z als LazyPrefixCollection<LazyDropWhileBidirectionalCollection<[Int]>> eingeben. Aber das ist nicht durch ganze Zahlen indexierbar. Ich weiß, es fühlt sich an wie es sein sollte, aber es ist nicht durch den aktuellen Compiler beweisbar. (siehe unten) Also Ihre [0] schlägt fehl. Und Backtracking ist nicht stark genug, um aus diesem verrückten Labyrinth herauszukommen. Es gibt einfach zu viele Überladungen mit unterschiedlichen Rückgabetypen, und der Compiler weiß nicht, welche Sie wollen.

Aber dieser spezielle Fall ist trivialerweise festgelegt:

print([0, 1, 2].lazy.drop(while: {_ in false}).prefix(2).first!) 

Das heißt, würde ich unbedingt vermeiden, dass die Compiler diese harte schieben. Das ist für Swift heute zu clever. Insbesondere Überladungen, die verschiedene Typen zurückgeben, sind in Swift sehr oft eine schlechte Idee. Wenn sie einfach sind, können Sie damit durchkommen. Aber wenn Sie mit dem Layern beginnen, verfügt der Compiler nicht über eine ausreichend starke Proof-Engine, um das Problem zu lösen. (Das heißt, wenn wir diese lange genug studiert, ich wette, es irgendwie tatsächlich nicht eindeutig ist, aber die Diagnose ist irreführend. Das ist eine sehr häufige Situation, wenn Sie in übermäßig klug Swift bekommen.)


Jetzt dass Sie es (in den Kommentaren) beschreiben, ist die Argumentation einfach.

LazyDropWhileCollection kann keinen ganzzahligen Index haben. Index-Subskriptionen müssen O (1) sein. Das ist die Bedeutung von Index im Vergleich zu anderen Indizes. (Der Index Index muss auch den Element Typ oder einen Absturz zurückgeben; er kann keinen Element? zurückgeben.Das ist viel gibt es eine DictionaryIndex die aus Key separaten ist.)

Da die Sammlung lazy ist und eine beliebige Anzahl Elemente fehlen, Nachschlagen eine bestimmte ganze Zahl „count“ (erste, zweite, etc.) ist O (n) . Es ist nicht möglich zu wissen, was das 100. Element ist, ohne mindestens 100 Elemente durchzugehen. Um eine Sammlung zu sein, muss ihr O (1) -Index in einer Form sein, die nur erzeugt werden kann, indem die Sequenz vorher durchlaufen wurde. Es kann nicht Int sein.

Dies ist wichtig, denn wenn man Code wie schreiben:

for i in 1...1000 { print(xs[i]) } 

Sie, dass in der Größenordnung von 1000 zu erwarten „Schritten“, aber wenn diese Sammlung einen ganzzahligen Index hätte, wäre es in der Größenordnung sein von 1 Million Schritten. Indem sie den Index umhüllen, verhindern sie, dass Sie diesen Code überhaupt schreiben. Das ist besonders wichtig in hoch generischen Sprachen wie Swift, wo Schichten von Allzweckalgorithmen leicht eine unerwartete O (n) -Operation in völlig unbrauchbare Leistung kaskadieren können (mit "nicht ausführbar" meine ich Dinge, von denen man erwartet, dass sie Millisekunden dauern) Minuten oder mehr).

+0

Vielen Dank für Ihre Antwort. Nach einigem Graben hat der Grund, dass '[0]' fehlschlägt, wahrscheinlich etwas mit 'drop (while:)' (und 'prefix (while:)') zu tun, das den darunterliegenden Index in einen 'LazyDropWhileIndex' (und' LazyPrefixWhileIndex') wickelt. . Dies ist eine 'Struktur', die eine implizite' init' hat (und daher nicht außerhalb der Standardbibliothek initialisiert werden kann). Alle anderen Typen, die mit 'LazyCollectionProtocol 'übereinstimmen, umhüllen ihre Indizes nicht, sondern" weiterleiten "den Index der zugrunde liegenden Basissammlung. (Es gibt wahrscheinlich gute Gründe für die Verpackung, die ich noch nicht vollständig verstehe.) –

+0

Vielen Dank für die Bearbeitung. Noch ein paar Gedanken. 'LazyPrefixWhileIndex' macht einen coolen Trick, bei dem 'endIndex' den Index der Basis-Sammlung ignoriert und nur einen' enum'-Wert zurückgibt, der den End-Index in O (1) darstellt. Das Schreiben von Unit-Tests für alles, was 'LazyPrefixWhileIndex' betrifft, ist unmöglich, da seine 'init' implizit ist und der darunterliegende Wert, der die Repräsentation des Indexes hält, 'internal' ist. Mit 'LazyDropWhileIndex' haben wir zumindest Zugriff auf den 'base'-Index, so dass wir ihn gegen eine Instanz des' Index'-Typs der Basis-Collection testen können. –

+0

Zusammenfassend kann ich den Grundgedanken hinter 'LazyPrefixWhileIndex' verstehen, aber für' LazyDropWhileIndex' hätten sie einfach den zugrunde liegenden Basisindex-Typ verwenden können. –

0

Ändern Sie die letzte Zeile dazu:

let x = [0, 1, 2] 

let lazyX: LazySequence    = x.lazy 
let lazyX2: LazyRandomAccessCollection = x.lazy 
let lazyX3: LazyBidirectionalCollection = x.lazy 
let lazyX4: LazyCollection    = x.lazy 

print(lazyX.drop(while: {_ in false}).prefix(2)[0]) 

können Sie feststellen, dass das Array 4 verschiedene faul Konformationen hat - Sie explizit sein müssen.

+0

Es ist mein Verständnis, dass die Überlastung, die höher in der Protokollkette ist, verwendet wird. Nach dem Compiler kann es nicht zwischen zwei Arten wählen; nämlich 'LazyRandomAccessCollection' und' Sequence'. (Was nicht sinnvoll ist, da 'Index (Position)' keine Methode von 'Sequenz' ist.) ' LazyRandomAccessCollection' wäre in diesem Fall die logische Wahl. –

Verwandte Themen