<div dir="ltr">+1 looks good, I had a go at implementing it and I think it may require changes not discussed in the proposal.<br><div><br></div><div>You&#39;ve covered the potential issues fairly well, to be a little more explicit these are the issues I&#39;ve found:</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"> 1) LazySequenceType&#39;s property array cannot be defined without an infinite sized array.<div> 2) what should [1,2,3].cycle.suffix(4) return? [3,1,2,3] probably has the least surprises, but it&#39;s like asking what&#39;s the number before infinity.</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div> 3) dropLast should return AnySequence(self), but requires specialisation, this may have to also be a fatalError (see below).<br></div></blockquote><div><br></div><div>One issue I don&#39;t think you&#39;ve mentioned, and I don&#39;t seem to be able to resolve is this:</div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div>let mySequence = [1,2,3].cycle.dropLast(1)</div></blockquote><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px">mySequence.suffix(7)</blockquote><div><br></div><div>This could have well defined behaviour (see part 2 above), however the implementation has some issues.</div><br>In this case mySequence is an AnySequence&lt;Int&gt;, mySequence.suffix(7) uses AnySequence&#39;s specialisation and so tries to iterate over the entire sequence to find the suffix. AnySequence&lt;Int&gt; is type-erased so there&#39;s no way to specialise when the underlying sequence is infinite (to get a valid implementation of suffix).<div><br></div><div>Potential solutions: </div><div> * Replace erased Any* types with a more flexible alternative that doesn&#39;t remove type information (higher kinded types perhaps).</div><div> * Replace SequenceType with two protocols FiniteSequenceType and InfiniteSequenceType, have type erased versions of each, duplicate all the things.<br></div><div> * Add a property to SequenceType to indicate if it&#39;s definitely finite (undefined?), AnySequence uses a different backing implementation depending on this boolean.</div><div><br></div><div>Here&#39;s the implementation I used in a playground to toy with this:</div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">public</span> <span style="color:rgb(187,44,162)">struct</span> CycleSequence&lt;Base : CollectionType&gt; : <span style="color:rgb(112,61,170)">LazySequenceType</span> {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">private</span> <span style="color:rgb(187,44,162)">let</span> base: <span style="color:rgb(112,61,170)">Base</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">private</span> <span style="color:rgb(187,44,162)">init</span>(<span style="color:rgb(187,44,162)">_</span> collection: <span style="color:rgb(112,61,170)">Base</span>) {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">self</span>.<span style="color:rgb(79,129,135)">base</span> = collection</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(187,44,162)"><span style="color:rgb(0,0,0)">    </span>@warn_unused_result</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">public</span> <span style="color:rgb(187,44,162)">func</span> generate() -&gt; <span style="color:rgb(79,129,135)">CycleGenerator</span>&lt;<span style="color:rgb(112,61,170)">Base</span>&gt; {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(0,0,0)">        </span><span style="color:rgb(187,44,162)">return</span><span style="color:rgb(0,0,0)"> </span>CycleGenerator<span style="color:rgb(0,0,0)">&lt;</span><span style="color:rgb(112,61,170)">Base</span><span style="color:rgb(0,0,0)">&gt;(</span>base<span style="color:rgb(0,0,0)">.</span><span style="color:rgb(61,29,129)">generate</span><span style="color:rgb(0,0,0)">)</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)">    </span><span style="color:rgb(187,44,162)">public</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">var</span><span style="color:rgb(0,0,0)"> array: [</span>Base<span style="color:rgb(0,0,0)">.</span>Generator<span style="color:rgb(0,0,0)">.</span>Element<span style="color:rgb(0,0,0)">] {</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(209,47,27)"><span style="color:rgb(0,0,0)">        </span><span style="color:rgb(61,29,129)">fatalError</span><span style="color:rgb(0,0,0)">(</span>&quot;This is undefined!&quot;<span style="color:rgb(0,0,0)">)</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">public</span> <span style="color:rgb(187,44,162)">struct</span> CycleGenerator&lt;Base : CollectionType&gt; : <span style="color:rgb(112,61,170)">GeneratorType</span> {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">private</span> <span style="color:rgb(187,44,162)">let</span> generatorProducer: () -&gt; <span style="color:rgb(112,61,170)">Base</span>.<span style="color:rgb(112,61,170)">Generator</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">private</span> <span style="color:rgb(187,44,162)">var</span> generator: <span style="color:rgb(112,61,170)">Base</span>.<span style="color:rgb(112,61,170)">Generator</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">private</span> <span style="color:rgb(187,44,162)">init</span>(<span style="color:rgb(187,44,162)">_</span> generatorProducer: () -&gt; <span style="color:rgb(112,61,170)">Base</span>.<span style="color:rgb(112,61,170)">Generator</span>) {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">self</span>.<span style="color:rgb(79,129,135)">generatorProducer</span> = generatorProducer</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">self</span>.<span style="color:rgb(79,129,135)">generator</span> = generatorProducer()</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(187,44,162)"><span style="color:rgb(0,0,0)">    </span>@warn_unused_result</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">public</span> <span style="color:rgb(187,44,162)">mutating</span> <span style="color:rgb(187,44,162)">func</span> next() -&gt; <span style="color:rgb(112,61,170)">Base</span>.<span style="color:rgb(112,61,170)">Generator</span>.<span style="color:rgb(112,61,170)">Element</span>? {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">if</span> <span style="color:rgb(187,44,162)">let</span> element = <span style="color:rgb(79,129,135)">generator</span>.<span style="color:rgb(61,29,129)">next</span>() {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">            <span style="color:rgb(187,44,162)">return</span> element</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(0,0,0)">        </span>generator<span style="color:rgb(0,0,0)"> = </span>generatorProducer<span style="color:rgb(0,0,0)">()</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">return</span> <span style="color:rgb(79,129,135)">generator</span>.<span style="color:rgb(61,29,129)">next</span>()</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(187,44,162)">extension</span><span style="color:rgb(0,0,0)"> </span>CycleSequence<span style="color:rgb(0,0,0)"> {</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(187,44,162)"><span style="color:rgb(0,0,0)">    </span>@warn_unused_result</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(0,0,0)">    </span><span style="color:rgb(187,44,162)">public</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">func</span><span style="color:rgb(0,0,0)"> dropLast(n: </span>Int<span style="color:rgb(0,0,0)">) -&gt; </span>AnySequence<span style="color:rgb(0,0,0)">&lt;</span>Base<span style="color:rgb(0,0,0)">.</span>Generator<span style="color:rgb(0,0,0)">.</span>Element<span style="color:rgb(0,0,0)">&gt; {</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">return</span> <span style="color:rgb(112,61,170)">AnySequence</span>(<span style="color:rgb(187,44,162)">self</span>)</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(187,44,162)"><span style="color:rgb(0,0,0)">    </span>@warn_unused_result</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    <span style="color:rgb(187,44,162)">public</span> <span style="color:rgb(187,44,162)">func</span> suffix(maxLength: <span style="color:rgb(112,61,170)">Int</span>) -&gt; <span style="color:rgb(112,61,170)">AnySequence</span>&lt;<span style="color:rgb(112,61,170)">Base</span>.<span style="color:rgb(112,61,170)">Generator</span>.<span style="color:rgb(112,61,170)">Element</span>&gt; {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">let</span> maxCount = <span style="color:rgb(79,129,135)">base</span>.<span style="color:rgb(112,61,170)">count</span>.<span style="color:rgb(61,29,129)">toIntMax</span>()</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">let</span> sequenceLength = maxCount &gt;= <span style="color:rgb(112,61,170)">Int</span>.max.<span style="color:rgb(61,29,129)">toIntMax</span>() ? <span style="color:rgb(112,61,170)">Int</span>.max : <span style="color:rgb(112,61,170)">Int</span>(maxCount)</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">if</span> maxLength &lt; sequenceLength {</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">            <span style="color:rgb(187,44,162)">return</span> <span style="color:rgb(112,61,170)">AnySequence</span>(<span style="color:rgb(79,129,135)">base</span>.<span style="color:rgb(61,29,129)">suffix</span>(maxLength))</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">        <span style="color:rgb(187,44,162)">return</span> <span style="color:rgb(187,44,162)">self</span>.<span style="color:rgb(61,29,129)">dropFirst</span>(sequenceLength - (maxLength % sequenceLength)).<span style="color:rgb(61,29,129)">prefix</span>(maxLength)</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">    }</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;min-height:13px"><br></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(112,61,170)"><span style="color:rgb(187,44,162)">extension</span><span style="color:rgb(0,0,0)"> </span>CollectionType<span style="color:rgb(0,0,0)"> {</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(79,129,135)"><span style="color:rgb(0,0,0)">    </span><span style="color:rgb(187,44,162)">public</span><span style="color:rgb(0,0,0)"> </span><span style="color:rgb(187,44,162)">var</span><span style="color:rgb(0,0,0)"> cycle: </span>CycleSequence<span style="color:rgb(0,0,0)">&lt;</span><span style="color:rgb(112,61,170)">Self</span><span style="color:rgb(0,0,0)">&gt; { </span><span style="color:rgb(187,44,162)">return</span><span style="color:rgb(0,0,0)"> </span>CycleSequence<span style="color:rgb(0,0,0)">(</span><span style="color:rgb(187,44,162)">self</span><span style="color:rgb(0,0,0)">) }</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">}</p></div></blockquote><div><br></div><div><br></div><blockquote style="margin:0px 0px 0px 40px;border:none;padding:0px"><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)">// this produces an infinite loop when evaluating .suffix(7)</p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo"><span style="color:rgb(187,44,162)">let</span> cycle = [<span style="color:rgb(209,47,27)">&quot;a&quot;</span>, <span style="color:rgb(209,47,27)">&quot;b&quot;</span>, <span style="color:rgb(209,47,27)">&quot;c&quot;</span>].<span style="color:rgb(79,129,135)">cycle</span></p></div><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(61,29,129)"><span style="color:rgb(79,129,135)">cycle</span><span style="color:rgb(0,0,0)">.</span><span style="color:rgb(49,89,93)">dropLast</span><span style="color:rgb(0,0,0)">(</span><span style="color:rgb(39,42,216)">1</span><span style="color:rgb(0,0,0)">).</span>suffix<span style="color:rgb(0,0,0)">(</span><span style="color:rgb(39,42,216)">7</span><span style="color:rgb(0,0,0)">).</span>forEach<span style="color:rgb(0,0,0)"> { </span>print<span style="color:rgb(0,0,0)">(</span><span style="color:rgb(209,47,27)">&quot;suffix: </span><span style="color:rgb(0,0,0)">\</span><span style="color:rgb(209,47,27)">(</span><span style="color:rgb(0,0,0)">$0</span><span style="color:rgb(209,47,27)">)&quot;</span><span style="color:rgb(0,0,0)">) }</span></p></div></blockquote><div><p style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo">
</p></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Dec 28, 2015 at 6:35 PM, Developer via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">+1.  Stream support is long overdue.<br>
<br>
~Robert Widmann<br>
<br>
2015/12/28 2:20、Kevin Ballard via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; のメッセージ:<br>
<div class="HOEnZb"><div class="h5"><br>
&gt; ## Introduction<br>
&gt;<br>
&gt; Add a new property `cycle` to CollectionType that returns an infinite SequenceType that yields the elements of the collection in a loop.<br>
&gt;<br>
&gt; ## Motivation<br>
&gt;<br>
&gt; It&#39;s sometimes useful to be able to have an infinite sequence. For example, `CollectionOfOne(x).cycle` could be used to have an infinite sequence of a single element (similar to Repeat but without a count). A common use for infinite sequences is zipping with a finite sequence. As far as I&#39;m aware, the stdlib does not currently provide any way to create such an infinite sequence.<br>
&gt;<br>
&gt; ## Proposed solution<br>
&gt;<br>
&gt; Extend CollectionType with a new property `cycle` that yields a type that conforms to SequenceType. This sequence yields each element of the collection in an infinite loop.<br>
&gt;<br>
&gt; ## Detailed design<br>
&gt;<br>
&gt; 2 new types would be added:<br>
&gt;<br>
&gt; struct CycleSequence&lt;Base : CollectionType&gt; : LazySequenceType { ... }<br>
&gt; struct CycleGenerator&lt;Base : CollectionType&gt; : GeneratorType { ... }<br>
&gt;<br>
&gt; CollectionType would be extended with a property:<br>
&gt;<br>
&gt; extension CollectionType {<br>
&gt;    public var cycle: CycleSequence&lt;Self&gt; { get }<br>
&gt; }<br>
&gt;<br>
&gt; This is an extension of CollectionType instead of SequenceType because it requires a multi-pass sequence (and SequenceType does not provide that guarantee). The returned type conforms to SequenceType instead of CollectionType because there is no possible `endIndex` that satisfies the requirement of being reachable from `startIndex` by zero or more applications of `successor()`.<br>
&gt;<br>
&gt; Because the default eager versions of map and filter will execute forever on an infinite sequence, CycleSequence conforms to LazySequenceType instead of SequenceType in order to provide lazy versions of those functions. Additionally, it will provide implementations of the eager versions that simply trigger a fatalError(), as the alternative is an infinite loop that consumes more and more memory.<br>
&gt;<br>
&gt; ## Impact on existing code<br>
&gt;<br>
&gt; None<br>
&gt;<br>
&gt; -Kevin Ballard<br>
&gt; _______________________________________________<br>
&gt; swift-evolution mailing list<br>
&gt; <a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
&gt; <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div>