Skip to content

Instantly share code, notes, and snippets.

@owensd owensd/iterate.swift Secret
Created Apr 13, 2016

Embed
What would you like to do?
struct LazyTakeWhileGenerator<Base : GeneratorType> : GeneratorType, SequenceType {
var base: Base
var predicate: Base.Element -> Bool
init(base: Base, takeWhile predicate: Base.Element -> Bool) {
self.base = base
self.predicate = predicate
}
mutating func next() -> Base.Element? {
if let n = base.next() where predicate(n) {
return n
}
return nil
}
}
extension LazySequenceType {
typealias ElementType = Self.Elements.Generator.Element
func takeWhile(predicate: ElementType -> Bool) -> LazyTakeWhileSequence<Self.Elements> {
return LazyTakeWhileSequence(base: self.elements, takeWhile: predicate)
}
}
struct LazyTakeWhileSequence<Base : SequenceType> : LazySequenceType {
let base: Base
let predicate: Base.Generator.Element -> Bool
init(base: Base, takeWhile predicate: Base.Generator.Element -> Bool) {
self.base = base
self.predicate = predicate
}
func generate() -> LazyTakeWhileGenerator<Base.Generator> {
return LazyTakeWhileGenerator(base: base.generate(), takeWhile: predicate)
}
}
struct StridingSequenceGenerator<Element> : GeneratorType, SequenceType {
let initial: Element
let stride: Element throws -> Element
var current: Element?
init(initial: Element, stride: Element throws -> Element) {
self.initial = initial
self.stride = stride
self.current = initial
}
mutating func next() -> Element? {
defer {
if let c = current {
current = try? stride(c)
}
else {
current = nil
}
}
return current
}
}
struct StridingSequence<Element> : LazySequenceType {
let initial: Element
let stride: Element throws -> Element
init(initial: Element, stride: Element throws -> Element) {
self.initial = initial
self.stride = stride
}
func generate() -> StridingSequenceGenerator<Element> {
return StridingSequenceGenerator(initial: initial, stride: stride)
}
}
func iterate<T>(initial from: T, stride: T throws -> T) -> StridingSequence<T> {
return StridingSequence(initial: from, stride: stride)
}
for n in iterate(initial: Int(1), stride: {$0 * 2}).takeWhile({ $0 < 10 }) {
print("\(n)", terminator: ", ")
}
print()
print("--")
let items = iterate(initial: Int(1), stride: {$0 * 2})
.filter({ $0 != 4})
.takeWhile({ $0 < 10 })
for n in items {
print("\(n)", terminator: ", ")
}
print()
print("--")
for var n = 1; n < 10; n = n * 2 {
print("\(n)", terminator: ", ")
}
@algal

This comment has been minimized.

Copy link

algal commented Jul 21, 2016

I'm not saying it's good but there is a much shorter way to get lazy iteration up to a bound by using the existing AnyGenerator type:

var i = 1
let g = AnyGenerator { () -> Int? in
  let val:Int? = (i < 10) ? i : nil
  i = i * 2
  return val
}

Now you can iterate thru the lazily generated sequence using the usual for .. in construct:

for j in g {
  print(i)
}

So this is much less code than you wrote, but it's problems are still pretty obvious: the counter variable i is still in scope after your iterations, the generator g is still in scope after your iteration, and worst of all the closure in the AnyGenerator is not very intuitive

You could also produce your own lazy generator that reproduces the C style for loop somewhat, and this would encapsulate those temporary variables:

struct ForIteration<Element>  : GeneratorType {
  var initial:Element
  let inc:Element->Element
  let cond:Element->Bool

  mutating func next() -> Element? {
    if cond(initial) == false {
      return nil
    }
    else {
      let currentVal = initial
      initial = inc(initial)
      return currentVal
    }
  }
}
extension ForIteration : SequenceType { }

let f = ForIteration<Int>(initial: 1,
                         inc: { $0*2 },
                         cond: { $0 < 10})

for j in f {
  print(j)
}

There are also many situations where you can get lazyness by just adding .lazy to existing sequences, collections, etc..

I agree with your larger point that the Swift standard library should include primitives that cover the case of the C-style loop more intuitively and with equivalent performance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.