+ 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]> 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 >>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
