That works, though it calls `next()` on an iterator twice as often as is necessary… Either way, it’s not that important. There are ways around not having an optional `first` parameter. When I brought it up I thought it was just an oversight, but now that it turns out it isn’t (and there are reasonable alternatives), I’m quite fine with its current implementation. :)
> On 30 Aug 2016, at 19:13, Max Moiseev <[email protected]> wrote: > > FWIW, the ‘classical’ way of doing what I think you’re trying to do is: > > extension Sequence { > var pairs: AnySequence<(Iterator.Element, Iterator.Element)> { > return AnySequence(zip(self, self.dropFirst())) > } > } > > Does it have the right behavior? > > Max > >> On Aug 29, 2016, at 9:45 AM, Tim Vermeulen via swift-evolution >> <[email protected]> wrote: >> >> The intent of my function wasn’t very clear, but it was supposed to return a >> sequence that contains *all* consecutive pairs, i.e. (0 ..< 4).pairs would >> result in [(0, 1), (1, 2), (2, 3)]. >> >>> on Fri Aug 26 2016, Tim Vermeulen<[email protected]>wrote: >>> >>>> This is when I first wanted to pass an optional for the `first` parameter: >>>> >>>> extension Sequence { >>>> >>>> /// Returns a sequence of pairs of consecutive elements >>>> /// of the sequence, in order. >>>> var pairs: AnySequence<(Iterator.Element, Iterator.Element)>{ >>>> var iterator = makeIterator() >>>> >>>> let firstPair = iterator.next().flatMap { first in >>>> iterator.next().map { second in (first, second) } >>>> } >>>> >>>> // I can't do this, because `firstPair` is optional >>>> let seq = sequence(first: firstPair) { _, second in >>>> guard let next = iterator.next() else { return nil } >>>> return (second, next) >>>> } >>>> >>>> return AnySequence(seq) >>>> } >>>> >>>> } >>>> >>>> In this particular case, finding a workaround is fairly easy (with a >>>> guard and `return AnySequence([])` in the `else` block). However, this >>>> becomes less elegant if you just want to iterate over it rather than >>>> wrap it in AnySequence. >>> This is why we have sequence(state:next:) >>> >>> >>> extension Sequence { >>> /// Returns a sequence of pairs of consecutive elements >>> /// of the sequence, in order. >>> var pairs: AnySequence<(Iterator.Element, Iterator.Element)>{ >>> return AnySequence( >>> sequence( >>> state: makeIterator(), >>> next: { (iter: inout Iterator) in >>> iter.next().flatMap { first in >>> iter.next().map { (first, $0) } >>> } >>> }) >>> ) >>> } >>> } >>> >>> for j in 0..<10 { >>> print(Array((0..<j).pairs)) >>> } >>> >>> HTH, >>> Dave >>>> >>>>> Hi Tim, >>>>> >>>>> After having a quick conversation with Dave, here is the question I >>>>> should have asked right away: can you share the typical problem you >>>>> are solving with your overload of the `sequence(first:next:)` >>>>> function? >>>>> >>>>> Max >>>>> >>>>> >>>>>> On Aug 20, 2016, at 2:26 AM, Tim >>>>>> Vermeulen<[email protected](mailto:[email protected])>wrote: >>>>>> What you’re saying makes sense, and I might not have brought this >>>>>> up in the first place if `first.map { sequence(first: $0, next: >>>>>> next } ?? []` worked. The main annoyance is that the best solution >>>>>> (currently) seems to be to copy the source code and make a change. >>>>>> >>>>>> (cc-ing Jordan Rose because of a related swift-users thread) This >>>>>> might be a bit of a stretch, but can’t Swift upcast sequences to >>>>>> AnySequence implicitly, like is done with AnyHashable? That would >>>>>> make `first.map { sequence(first: $0, next: next } ?? []` >>>>>> instantly valid, I think. There’s also something to be said for >>>>>> consistency between type erasers. (I’m not necessarily talking >>>>>> about Swift 3) >>>>>>> On 20 Aug 2016, at 02:22, Max >>>>>>> Moiseev<[email protected](mailto:[email protected])>wrote: >>>>>>> Hi Tim, >>>>>>> >>>>>>> I still believe that having 2 termination conditions is >>>>>>> wrong. But I guess we need a tie breaker here, someone with a >>>>>>> strong opinion about the problem. >>>>>>> As Kevin mentioned we are very late in the release process, so >>>>>>> waiting for another opinion for a day or two won’t change >>>>>>> anything, really. >>>>>>> >>>>>>> Meanwhile, I played a little bit with an idea of making `first.map { >>>>>>> sequence(first $0, next: next} ?? []` work. >>>>>>> Turns out, if we add an `ExpressibleByArrayLiteral` protocol >>>>>>> conformance to the `UnfoldSequence`, this snippet will compile >>>>>>> just fine. One downside is that the `ExpressibleByArrayLiteral` >>>>>>> protocol allows creating non-empty sequences as well, which does >>>>>>> not make sense for the `UnfoldSequence`. >>>>>>> >>>>>>> >>>>>>> Max >>>>>>> >>>>>>>> On Aug 19, 2016, at 3:48 PM, Tim Vermeulen via >>>>>>>> swift-evolution<[email protected](mailto:[email protected])>wrote: >>>>>>>>> >>>>>>>>> On 19 Aug 2016, at 19:48, Kevin >>>>>>>>> Ballard<[email protected](mailto:[email protected])>wrote: >>>>>>>>> AFAIK this issue has never been discussed with >>>>>>>>> sequence(first:next:) before. It certainly wasn't brought up >>>>>>>>> during review. >>>>>>>>> >>>>>>>>> As for my opinion, I'm really not sure. I was going to point >>>>>>>>> out that right now sequence(first:next:) guarantees that the >>>>>>>>> first element of the resulting sequence is the value >>>>>>>>> provided as "first", but it occurs to me that if you treat >>>>>>>>> the nil result from next() as an element, then this still >>>>>>>>> holds true. So I guess my biggest worry is this change will >>>>>>>>> make it harder to use sequence(first:next:) to produce >>>>>>>>> sequences of optional values. >>>>>>>> >>>>>>>> I don’t think producing sequences of optional values would >>>>>>>> really be a problem, because type inference will figure this >>>>>>>> out based on whether you treat the argument to the `next` >>>>>>>> closure as an optional or not. And if you only do things in >>>>>>>> `next` that work both with optionals and non-optionals (very >>>>>>>> unlikely), you can always manually specify the type of the >>>>>>>> sequence. >>>>>>>>> So I guess I'm ambivalent, and would prefer to defer to the wisdom of >>>>>>>>> the Swift core team on this matter. >>>>>>>>> >>>>>>>>> That said, didn't the deadline for source-breaking changes already >>>>>>>>> come and go? >>>>>>>>> >>>>>>>>> -Kevin Ballard >>>>>>>>> >>>>>>>>> On Fri, Aug 19, 2016, at 10:37 AM, Max Moiseev wrote: >>>>>>>>>> + Erica, Kevin, as the authors of the original proposal. >>>>>>>>>> >>>>>>>>>> Do you remember the problem of non-emptiness being >>>>>>>>>> discussed before? And if not, what’s your opinion on the >>>>>>>>>> proposed change? >>>>>>>>>> >>>>>>>>>> Thanks, >>>>>>>>>> Max >>>>>>>>>> >>>>>>>>>>> On Aug 19, 2016, at 7:53 AM, Tim >>>>>>>>>>> Vermeulen<[email protected](mailto:[email protected])>wrote: >>>>>>>>>>> >>>>>>>>>>> Hi Max, thanks for having a look. >>>>>>>>>>> >>>>>>>>>>> A big part of why I’m not really happy with the current >>>>>>>>>>> implementation is that the function always produces a >>>>>>>>>>> nonempty sequence, though the compiler doesn’t know >>>>>>>>>>> it. `sequence(first: first, next: next).last` returns an >>>>>>>>>>> optional, even though it can’t possibly be nil. The same >>>>>>>>>>> goes for something like `sequence(first: 5, next: { $0 * >>>>>>>>>>> 3 }).first(where: { $0>1000 })`, because the sequence is >>>>>>>>>>> infinite, which means `first(while:)` will either keep >>>>>>>>>>> running forever, or return a non-optional. >>>>>>>>>>> >>>>>>>>>>> Ideally, we’d have three types of sequences, with three >>>>>>>>>>> corresponding `sequence(first:next:)` functions: >>>>>>>>>>> >>>>>>>>>>> func sequence<T>(first: T?, next: (T) ->T?)—returns any sequence >>>>>>>>>>> func sequence<T>(first: T,next: (T) ->T?)—returns a nonempty >>>>>>>>>>> sequence >>>>>>>>>>> func sequence<T>(first: T,next: (T) ->T)—returns an infinite >>>>>>>>>>> sequence >>>>>>>>>>> >>>>>>>>>>> Default implementations for methods on sequences would >>>>>>>>>>> either return optionals or non-optionals depending on >>>>>>>>>>> their emptiness/finiteness. We just have the first kind >>>>>>>>>>> of sequence right now, so in that regard it would make >>>>>>>>>>> sense to also give `sequence(first:next)` the >>>>>>>>>>> corresponding signature.Later, when the language / >>>>>>>>>>> standard library supports the other two kinds of >>>>>>>>>>> sequences (if that ever happens), the other versions >>>>>>>>>>> could be added. >>>>>>>>>>> >>>>>>>>>>> Another reason that makes me think that the version that >>>>>>>>>>> accepts an optional `first` argument is more natural, is >>>>>>>>>>> the fact that the function body doesn’t need to be >>>>>>>>>>> changed at all. It supports optional seeds by design; >>>>>>>>>>> only the signature prevents it. >>>>>>>>>>> >>>>>>>>>>> I know these arguments might not be very convincing, but >>>>>>>>>>> I feel like Swift misses an opportunity if it >>>>>>>>>>> unnecessarily constrains the `first` parameter to be >>>>>>>>>>> non-optional. The `.lazy.flatMap({ $0 })` alternative >>>>>>>>>>> that you pointed out does work, but it makes everything >>>>>>>>>>> very unreadable: not just the `.lazy.flatMap({ $0 })` >>>>>>>>>>> part, but also the body of the `next` parameter because >>>>>>>>>>> you’re now dealing with optionals (i.e. you have to >>>>>>>>>>> `flatMap` over the closure argument). The best solution >>>>>>>>>>> I’ve come up with is to copy the `sequence(first:next)` >>>>>>>>>>> implementation from the source code and change the >>>>>>>>>>> signature. :-/ >>>>>>>>>>> >>>>>>>>>>> `sequence(state:next:)` isn’t very appropriate for this >>>>>>>>>>> task either, because naive usage with an optional seed >>>>>>>>>>> has the downside of being unnecessarily eager just like >>>>>>>>>>> a naive `sequence(first:next)` implementation (as >>>>>>>>>>> described in a comment in the source code). >>>>>>>>>>> >>>>>>>>>>>> On 19 Aug 2016, at 00:18, Max >>>>>>>>>>>> Moiseev<[email protected](mailto:[email protected])>wrote: >>>>>>>>>>>> >>>>>>>>>>>> Hi Tim, >>>>>>>>>>>> >>>>>>>>>>>> Thanks for bringing this up. >>>>>>>>>>>> Here are my thoughts on the change you’re proposing. >>>>>>>>>>>> >>>>>>>>>>>> func sequence<T>(first: T, next: (T) ->T?) ->UnfoldFirstSequence<T> >>>>>>>>>>>> >>>>>>>>>>>> To me the type of the function as it is tells a clear >>>>>>>>>>>> story of what’s going to happen: take the `first`, >>>>>>>>>>>> make it a head of the resulting sequence, and then try >>>>>>>>>>>> to produce the tail by a series of applications of >>>>>>>>>>>> `next`. The only thing that controls when the sequence >>>>>>>>>>>> generation terminates is the result of `next`. >>>>>>>>>>>> >>>>>>>>>>>> If we change the type of `first` to an Optional<T>, it >>>>>>>>>>>> would make the termination condition >>>>>>>>>>>> non-trivial. After all, the only thing it would do is >>>>>>>>>>>> try to unwrap the `first`, before doing what it needs >>>>>>>>>>>> to, but we already have a `map` for that. One should >>>>>>>>>>>> be able to simply do the `first.map { sequence(first: >>>>>>>>>>>> $0, next: next) } ?? []` but that won’t work with the >>>>>>>>>>>> types very well, unfortunately. >>>>>>>>>>>> >>>>>>>>>>>> As an alternative, `let first: Int? = ...; >>>>>>>>>>>> sequence(first: first, next: next).flatMap({$0})` (or >>>>>>>>>>>> even `.lazy.flatMap({$0})`) will do the right thing >>>>>>>>>>>> without making an API more complex. >>>>>>>>>>>> >>>>>>>>>>>> I see the point of `sequence(first:next:)` to be >>>>>>>>>>>> precisely the "generate the non-empty sequence using a >>>>>>>>>>>> seed and a simple producer", for anything more than >>>>>>>>>>>> that, there is `sequence(state:next:)`. >>>>>>>>>>>> >>>>>>>>>>>> What do you think? >>>>>>>>>>>> >>>>>>>>>>>> Max >>>>>>>>>>>> >>>>>>>>>>>>> On Aug 14, 2016, at 4:27 PM, Tim Vermeulen via >>>>>>>>>>>>> swift-evolution<[email protected](mailto:[email protected])>wrote: >>>>>>>>>>>>> >>>>>>>>>>>>> sequence(first:next:) takes a non-optional first >>>>>>>>>>>>> argument. Is there a reason for that? >>>>>>>>>>>>> sequence(state:next:) allows empty sequences, and I >>>>>>>>>>>>> don’t see why sequence(first:next:) shouldn’t. The >>>>>>>>>>>>> fix would be to simply add the `?` in the function >>>>>>>>>>>>> signature; no other changes are required to make it >>>>>>>>>>>>> work. >>>>>>>>>>>>> >>>>>>>>>>>>> I considered just filing a bug report, but since this is a change >>>>>>>>>>>>> of the public API... >>>>>>>>>>>>> _______________________________________________ >>>>>>>>>>>>> swift-evolution mailing list >>>>>>>>>>>>> [email protected](mailto:[email protected]) >>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>>>> >>>>>>>> _______________________________________________ >>>>>>>> swift-evolution mailing list >>>>>>>> [email protected](mailto:[email protected]) >>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> [email protected] >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> -- >>> -Dave >>> >>> >>> >>> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution > _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
