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

Seth Friedman sethfri at gmail.com
Mon Jan 11 00:38:25 CST 2016


Yes, thank you!
On Sun, Jan 10, 2016 at 10:28 PM Kevin Ballard <kevin at sb.org> wrote:

> Sounds like you want usage examples, then. Are the ones I gave useful?
>
> -Kevin Ballard
>
> On Sun, Jan 10, 2016, at 10:26 PM, Seth Friedman wrote:
>
> I wasn't suggesting you should convince the reviewers of the merits of
> functional style programming. I'm coming at it from the perspective of "Hey
> I'm not very familiar with functional style. What cool new things could
> these functions help me do if they're added to the stdlib?".
>
> Not all of your reviewers are necessarily going to be familiar with these
> functions from other languages; I simply think more detail would make the
> proposal more compelling. Ultimately up to you.
>
> Thanks,
> Seth
> On Sun, Jan 10, 2016 at 10:20 PM Kevin Ballard <kevin at sb.org> wrote:
>
> When the proposal is "we have a bunch of functions that match functions
> used in other languages, lets add a few more from the same category of
> functions that we missed", does there really need to be much explanation
> beyond "they're useful in the other languages that have them, they'd be
> useful for the same reasons in Swift"?
>
> If requested, I can provide examples of usage. But if you're not already
> sold on the benefits of working with sequences in a functional manner, it's
> out of scope of the proposal to convince you of the merits of that style of
> programming. And if you are already sold on the benefits of doing so, then
> adding these functions shouldn't need much explanation.
>
> Here's a few toy examples, if it helps:
>
> // list of all powers of 2 below some limit
> iterate(1, apply: { $0 * 2 }).takeWhile({ $0 < limit })
>
> // first "word" of a string, skipping whitespace
> let cs = NSCharacterSet.whitespaceCharacterSet()
> String(str.unicodeScalars.skipWhile({ cs.longCharacterIsMember($0.value) })
>                          .takeWhile({ !cs.longCharacterIsMember($0.value)
> }))
>
> // running total of an array of numbers
> numbers.scan(0, combine: +).dropFirst()
>
> // infinite fibonacci sequence
> iterate((0,1), apply: { ($1, $0+$1) }).lazy.map({$1})
>
> -Kevin Ballard
>
> On Sun, Jan 10, 2016, at 09:55 PM, Seth Friedman wrote:
>
> To clear my thoughts up a bit, that wasn't an "I'm too lazy to Google what
> these functions normally do" comment, but rather an "I believe proposals
> should provide as much context as possible about what you'd like to add
> along with the benefits of doing so" comment.
> On Sun, Jan 10, 2016 at 9:48 PM Seth Friedman <sethfri at gmail.com> wrote:
>
> I'm not familiar with any of the functions listed and would love to see
> more about them and their usefulness to Swift as part of the proposal.
>
> Thanks!
>
> Seth
> On Sat, Jan 9, 2016 at 5:30 PM Kevin Ballard via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Proposal PR submitted as https://github.com/apple/swift-evolution/pull/95
>
> -Kevin Ballard
>
> On Mon, Dec 28, 2015, at 03:59 PM, Kevin Ballard 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.
> >
> > ## 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
>
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160111/70322313/attachment.html>


More information about the swift-evolution mailing list