+ 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

Reply via email to