神刀安全网

Swift: The joy of sequences

I am really happy with how SE-0094 turned out. I helped with the paperwork but it was all Kevin Ballard ‘s brain child, putting together the two new sequence functions. If you haven’t been playing with these yet, they’re available in the latest developer snapshots (both the main trunk and the public branch) and they’re delightful.

There are two variations:

public func sequence<T>(first: T, next: (T) -> T?) ->      UnfoldSequence<T, (T?, Bool)>  public func sequence<T, State>(state: State, next: (inout State) -> T?) ->      UnfoldSequence<T, State>

The first one just takes a value, and then keeps applying a function to it, the second allows you to store associated state, meaning you can build functions like this:

extension Sequence {     // Not to spec: missing throwing, noescape     public func prefix(         while predicate: (Self.Iterator.Element) -> Bool) ->              UnfoldSequence<Self.Iterator.Element, Self.Iterator> {         return sequence(state: makeIterator(), next: {             (myState: inout Iterator) -> Iterator.Element? in             guard let next = myState.next() else { return nil }             return predicate(next) ? next : nil         })     } }

The preceding example showcases a very rough preview of the prefix(while:) function that will appear when SE-0045 gets implemented. In this version, I used   sequence to generate a series of elements while a predicate returns true. And yes, a few items are still less than ideal: you have to use a full type signature when using  inout parameters in a closure, so things get a little wordy.

If you were using the old AnySequence/AnyGenerator (or Sequence/AnyIterator) approach, you’d create the iterator separately. Something along these lines:

public func prefix(while predicate: (Self.Iterator.Element) -> Bool) -> AnySequence<Self.Iterator.Element> {     var iterator = self.makeIterator()     return AnySequence {         return AnyIterator {             guard let next = iterator.next() else { return nil }             return predicate(next) ? next : nil         }     } }

Incorporating the state into the sequence generator simplifies nearly any stream of data that’s more complex than a mathematical progression:

sequence(first: 1, next: { $0 + 2 })

You can imagine any kind of function being used here, whether additive, multiplicative, etc. (Of course, you can probably imagine a series of powers of two, which of course, pops back to the state version. I love that state version.)

Pairing prefix with sequence lets a few tiny fireworks get started:

Count to 10:

for i in sequence(first: 1, next: { $0 + 1 })     .prefix(while: { return $0 <= 10 }) {     print(i) }

Powers of 2 to 8192:

for i in sequence(state: 0, next: {      (idx: inout Int) -> Int in     defer { idx += 1 }; return Int(exp2(Double(idx)))})     .prefix(while: {return $0 <= 8192}) {     print(i) }

Speaking of wordiness, Swift still doesn’t support 2^n exponentiation, and when chaining in this way, you can’t use trailing closure syntax due to compiler confusion.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Swift: The joy of sequences

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址