-
-
Save owensd/8c52dfb300ebdd2b5c065ae10869490b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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: ", ") | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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:Now you can iterate thru the lazily generated sequence using the usual
for .. in
construct: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 intuitiveYou could also produce your own lazy generator that reproduces the C style for loop somewhat, and this would encapsulate those temporary variables:
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.