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

Dave Abrahams dave at boostpro.com
Sat Mar 5 23:38:06 CST 2016

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
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


More information about the swift-evolution mailing list