> On 19 Aug 2016, at 19:48, Kevin Ballard <ke...@sb.org> 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 <tvermeu...@me.com >>> <mailto:tvermeu...@me.com>> 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 <mois...@apple.com >>>> <mailto:mois...@apple.com>> 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 >>>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> 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 >>>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution