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.

> 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

Reply via email to