Skip to content

Instantly share code, notes, and snippets.

@alexlee002
Forked from pgherveou/generator.swift
Created June 22, 2021 03:17
Show Gist options
  • Save alexlee002/bf64d2cdb4cd01bf9bcd909bb7883d69 to your computer and use it in GitHub Desktop.
Save alexlee002/bf64d2cdb4cd01bf9bcd909bb7883d69 to your computer and use it in GitHub Desktop.
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
/// define an operation success or error result
enum Result<T> {
case error(Error)
case success(T)
}
/// define a generator function result.
/// a generator can yield multiple values before returning
enum IteratorResult<Yield, Return> {
case yield(Yield)
case done(Return)
}
/// a generator is a function that return an IteratorResult every time its called
typealias Generator<Yield, Return, Next> = (Next?) -> IteratorResult<Yield, Return>
typealias Thunk<T> = (@escaping (Result<T>) -> Void) -> Void
/// run a generator step bt step until its done
func runner<T, V>(_ generator: Generator<Thunk<T>, Thunk<V>, T>) -> Void {
func run(value: T?, callback: @escaping (Result<V>) -> Void) {
let it = generator(value)
switch it {
case .yield(let thunk):
thunk() { (result: Result<T>) -> Void in
switch result {
case .error(let err):
callback(.error(err))
case .success(let value):
print("yield", value)
return run(value: value, callback: callback)
}
}
case .done(let thunk):
thunk(callback)
}
}
run(value: nil) { print($0) }
}
/// example of generator that yield incremented number and returns 10
func incGenerator() -> Generator<Thunk<Int>, Thunk<Int>, Int> {
return { (prev: Int?) in
let next = (prev ?? 0) + 1
let thunk: Thunk<Int> = { callback in
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
callback(Result.success(next))
}
}
return next < 10
? .yield(thunk)
: .done(thunk)
}
}
runner(incGenerator())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment