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

Reply via email to