[swift-evolution] Proposal: Add scan, takeWhile, dropWhile, and iterate to the stdlib

Thorsten Seitz tseitz42 at icloud.com
Sun Mar 6 09:10:46 CST 2016


> Am 06.03.2016 um 06:38 schrieb Dave Abrahams via swift-evolution <swift-evolution at swift.org>:
> 
> 
>> on Mon Dec 28 2015, Kevin Ballard <swift-evolution-AT-swift.org> wrote:
>> 
>> ## Introduction
>> 
>> Add a few more functional sequence utilities to the standard library.
>> 
>> ## Motivation
>> 
>> We have map, filter, and reduce, but we're missing a bunch of useful
>> utilities like scan, iterate, takeWhile, and dropWhile. Interestingly,
>> the stdlib includes an implementation of scan in the doc comment for
>> LazySequenceType, it just doesn't actually provide it as API.
> 
> One of my concerns here is that while map, filter, and reduce are mostly
> “lingua franca” terms-of-art among programmers everywhere, these others
> are much less commonly-known and some of them aren't very descriptive of
> what they do.  There are lots more like these in the FP lexicon.  It was

I for one would love to see them added to the stdlib.

-Thorsten 

> easy to draw the line at map/filter/reduce (which also don't follow the
> usual grammar for API guidelines), but if we take the ones in this
> proposal, where do we stop?
> 
> Because your PR has comments describing these methods (i.e. it's more
> complete) I'll leave further remarks there.
> 
>> 
>> ## Proposed solution
>> 
>> We extend SequenceType with 3 new methods scan, takeWhile, and dropWhile. We also add a single global function iterate.
>> 
>> ## Detailed design
>> 
>> We add the following extension to SequenceType:
>> 
>> extension SequenceType {
>>    func scan<T>(initial: T, @noescape combine: (T, Self.Generator.Element) throws -> T) rethrows -> [T]
>>    func dropWhile(@noescape dropElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]
>>    func takeWhile(@noescape takeElement: (Self.Generator.Element) throws -> Bool) rethrows -> [Self.Generator.Element]
>> }
>> 
>> These all take functions, so to follow convention they're @noescape
>> and return arrays. We also provide an extension of CollectionType that
>> overrides a couple of these methods:
>> 
>> extension CollectionType {
>>    func dropWhile(@noescape dropElement: (Self.Generator.Element) throws -> Bool) rethrows -> Self.SubSequence
>>    func takeWhile(@noescape takeElement: (Self.Generator.Element) throws -> Bool) rethrows -> Self.SubSequence
>> }
>> 
>> We also provide lazy versions:
>> 
>> extension LazySequenceType {
>>    func scan<T>(initial: T, combine: (T, Self.Generator.Element) -> T) -> LazyScanSequence<Self.Elements, T>
>>    func dropWhile(dropElement: (Self.Generator.Element) -> Bool) -> LazyDropWhileSequence<Self.Elements>
>>    func takeWhile(takeElement: (Self.Generator.Element) -> Bool) -> LazyTakeWhileSequence<Self.Elements>
>> }
>> 
>> extension LazyCollectionType {
>>    func dropWhile(dropElement: (Self.Generator.Element) -> Bool) -> LazyDropWhileCollection<Self.Elements>
>>    func takeWhile(takeElement: (Self.Generator.Element) -> Bool) -> LazyTakeWhileCollection<Self.Elements>
>> }
>> 
>> No collection variant of scan is provided because that would require
>> storing the last value in the index itself, which would cause problems
>> if the combine function isn't pure.
>> 
>> LazyDropWhileCollection would behave similarly to LazyFilterCollection
>> in that it runs the predicate against the elements to drop when
>> accessing startIndex; unlike LazyFilterCollection, because there's
>> nothing else to skip after that point, the index itself can actually
>> be Self.Elements.Index (just like a slice). LazyTakeWhileCollection
>> also runs the predicate against the first element when accessing
>> startIndex, but it does need a unique index type (because endIndex has
>> to be some sentinel value, as it doesn't know where the end is until
>> you reach that point; this index type would therefore only conform to
>> ForwardIndexType).
>> 
>> And finally, we provide a global function
>> 
>> func iterate<T>(initial: T, _ f: T -> T) -> IterateSequence<T>
>> 
>> This function is inherently lazy and yields an infinite list of nested
>> applications of the function, so iterate(x, f) yields a sequence like
>> [x, f(x), f(f(x)), ...].
>> 
>> -Kevin Ballard
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> -- 
> -Dave
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution


More information about the swift-evolution mailing list