2017-09-16 13 views
1

なぜthis exampleがあいまいであるのか分かりません。 (ここにコードを追加しないと謝罪していますが、長すぎます)'怠け者'のあいまいな使用

LazyDropWhileBidirectionalCollectionに追加しました。 subscript(position)は、LazyPrefixCollectionで定義されています。しかし、上記の例から、次のコードは曖昧であってはならない、まだそれは次のとおりです。

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

プロトコル階層でアップ高いです過負荷が使用されますというのが私の理解です。

コンパイラによると、2つのタイプの中から選択することはできません。すなわちLazyRandomAccessCollectionおよびLazySequenceである。 (subscript(position)は、LazySequenceの方法ではないので意味がありません。LazyRandomAccessCollectionがここでは論理的に選択されます。

私は添字を削除した場合、それは動作します:

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

問題である可能性があり何?

+1

コンパイラの出力に、「レイジー」の候補が2つあります。 –

+1

関連する「問題コード」を投稿してください。 – shallowThought

+0

@shallowThought関連する問題コードは、最初の文のリンクの最後の行です。上記の投稿に追加しました。 –

答えて

1

ここのトレイルはあまりにも複雑であいまいです。要素を削除することでこれを見ることができます。特に、最後の添字ドロップ:この構成では

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

を、コンパイラはLazyPrefixCollection<LazyDropWhileBidirectionalCollection<[Int]>>としてzを入力したいと考えています。しかし、これは整数では索引付けできません。 私はそれがそうであるように感じますが、現在のコンパイラでは証明できません。 (下記参照)[0]が失敗します。バックトラックはこの狂った迷路から抜け出すほど強力ではありません。異なる戻り値の型を持つオーバーロードが多すぎるため、コンパイラは必要なものを知りません。

は、しかし、この特定のケースは自明固定されている:言わ

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

は、私は絶対にコンパイラにこのハードを押して避けるだろう。今日はスウィフトのためにこれはすべて賢明です。特に、さまざまなタイプを返すオーバーロードは、Swiftの非常に悪い考えです。彼らがシンプルなとき、はい、あなたはそれを手放すことができます。しかし、レイヤーを開始すると、コンパイラーはそれを解決するための十分な堅牢なエンジンを持っていません。 (私たちは十分な長さ、私はそれが実際に何らかの形で曖昧で賭けているこれを研究している場合それは、言っていますが、過度に賢いスウィフトに入る際に誤解された診断は。それは非常に一般的な状況です。)今


それを(コメントの中で)記述すると、推論は簡単です。

LazyDropWhileCollectionは整数のインデックスを持つことができません。索引添字はO(1)である必要があります。それはIndexサブスクリプトと他のサブスクリプトの意味です。 (Indexサブスクリプトもタイプを返すか、クラッシュする必要があります。Element?を返すことはできません。それはDictionaryIndexKeyとは別のものです)

コレクションが遅延していて、不足している要素が任意であるため、特定の整数「カウント」(第1、第2など)を検索するとO(n) 。少なくとも100要素を通らずに100番目の要素が何であるかを知ることはできません。コレクションであるためには、そのO(1)インデックスは、以前にシーケンスを歩いたことによってのみ作成できる形式でなければなりません。 Intにはできません。

あなたのようなコードを書くときので、これは重要です:

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

あなたはそれが1000年のオーダーであることを期待する「手順、」このコレクションは整数のインデックスを持っていたならば、それは順番になります100万歩のインデックスをラップすることで、最初にそのコードを書くことができなくなります。

これは、Swiftのような非常に一般的な言語では、汎用アルゴリズムのレイヤーが予期せぬO(n)操作を完全に実行不可能なパフォーマンスに簡単にカスケードすることができる場合に特に重要です(「実行不可能」とは、分以上)。

+0

ありがとうございます。 '' LazyDropWhileIndex''と '' LazyPrefixWhileIndex''の下位インデックスをラップする '' drop(while:) ''と '' prefix(while: 。これは暗黙の 'init'を持つ(したがって標準ライブラリの外では初期化することができない)' struct'です。 'LazyCollectionProtocol'に準拠する他のすべての型は、それらのインデックスをラップしませんが、基底のベースコレクションのインデックスを 'forward'します。 (私がまだ完全に理解していないラッピングの理由はおそらくあります。) –

+0

ありがとうございました。いくつかの考え。 'LazyPrefixWhileIndex'は、' endIndex'がベースコレクションのインデックスを無視し、O(1)の終了インデックスを表す 'enum'値を返すだけのクールなトリックを行います。 'LazyPrefixWhileIndex'を含む何かのユニットテストを書くことは、' init'が暗黙的で、インデックスの表現を保持する下位の値が 'internal'なので不可能です。 'LazyDropWhileIndex'では、少なくとも' base'インデックスにアクセスできるので、ベースコレクションの 'Index'タイプのインスタンスに対してこれをテストできます。 –

+0

結論として、私は 'LazyPrefixWhileIndex'の背後にある推論を理解することができますが、' LazyDropWhileIndex'のために彼らは基本的な 'Index'型を使ったばかりです。 –

0

変更し、これに最後の行:

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]) 

あなたは、アレイは、4体の異なる怠惰な立体構造を持っていることに気づくことができます - あなたは、明示的である必要があります。

+0

プロトコルチェーンの上位にある過負荷が使用されると私は理解しています。 コンパイラによれば、2つのタイプの中から選択することはできません。 'LazyRandomAccessCollection'と' Sequence'です。 ( 'subscript(position)'は 'Sequence'のメソッドではないので意味がありません。) この場合、' LazyRandomAccessCollection'が論理的に選択されます。 –

関連する問題