> 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

Reply via email to