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 <tvermeu...@me.com> 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 <mois...@apple.com >> <mailto:mois...@apple.com>> 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 >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >>> >>>> >>>> On 19 Aug 2016, at 19:48, Kevin Ballard <ke...@sb.org >>>> <mailto: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 <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