:orphan: Python popularized the concept of generators, resumable functions that lazily produce a sequence of values. For example, one could write a lazy UTF8 encoder like so:: func encodeUTF8< S: Sequence where S.Element == UnicodeScalar >(s: Sequence) -> GeneratorFunc { for scalar in s { let value = UInt32(scalar) switch value { case 0..0x7F: yield UInt8(value) case 0x80..0x7FF: yield 0xC0 | UInt8(value >> 6 ) yield 0x80 | UInt8(value & 0x3F) case 0x800..0xFFFF: yield 0xE0 | UInt8(value >> 12 ) yield 0x80 | UInt8(value >> 6 & 0x3F) yield 0x80 | UInt8(value & 0x3F) case 0x1_0000..0x10_FFFF: yield 0xF0 | UInt8(value >> 18 ) yield 0x80 | UInt8(value >> 12 & 0x3F) yield 0x80 | UInt8(value >> 6 & 0x3F) yield 0x80 | UInt8(value & 0x3F) } } } Generators are extremely popular in Python and have since been ported to other popular languages including C# and Javascript. Generators provide a solution to an instance of the **inversion of control** problem, wherein an algorithm with a naturally sequential definition, such as UTF-8 decoding above, needs to yield control to another algorithm in order. Without generators, awkward state machine types need to be manually written, obscuring the algorithm being expressed. Python and Javascript have extended their generators so that ``yield`` is a bidirectional operation, and C# has added ``async`` functions, which use a similar inversion-of-control transform to make asynchronous code readable. This proposal aims to provide a single language-level feature for inversion of control that is general enough to support both traditional generator functions as well as other useful inversion-of-control patterns, such as sink functions, ``async/await``-like asynchronous tasks, and general monadic control flow. Yieldable types --------------- A type is a **yieldable type** if it conforms to the ``Yieldable`` protocol:: protocol Yieldable { // The type that is output at each continuation point of the generator. typealias ContinuationType // Prime the generator with the entry point continuation. class func start(entry: () -> ContinuationType) -> Self } In addition to the formal requirements of the ``Yieldable`` protocol, the type must have class methods ``\`yield\``` and ``\`return\```, which may be overloaded arbitrarily as long as they follow these patterns (where ``_`` can be an arbitrary type):: // Yield a value from the generator, and accept a continuation function // pointer to resume the generator. class func `yield`(value: _, next: _ -> ContinuationType) -> ContinuationType // Return the final value from the generator. class func `return`(value: _) -> ContinuationType The ``yield`` Expression and Generator Transform ------------------------------------------------ If a function returns a yieldable type, and the function body contains one or both of: - a ``yield`` expression, or - a ``return`` statement matching the yieldable type's ``\`return\``` method's argument type, then the function body undergoes generator transformation. The function is turned "inside out" at every ``yield`` expression; the ``yield`` expression becomes a call to the yieldable type's ``\`yield\``` method with the operand to yield and a continuation closure that resumes execution of the function body. ``return`` statements in the generator get mapped to a call to the yieldable type's ``\`return\``` method. At the top level, the entry point to the function body is passed as a closure into the yieldable type's ``start`` method to form the formal result of the generator function. As an example, this function:: func foo() -> YieldableType { return yield (yield (yield 1) + 2) + 3 } would be turned into the equivalent of:: func foo() -> YieldableType { return YieldableType.start { return YieldableType.`yield`(1) { return YieldableType.`yield`($0 + 2) { return YieldableType.`return`($0 + 3) } } } } When ``yield`` appears amid more complex control flow, the transformation can be viewed as wrapping the function body in a Duff's device. For example, this generator:: func fibonacci() -> GeneratorFunc { var (a, b) = (0, 1) while true { yield b (a, b) = (b, a + b) } } could be thought of as being rewritten to:: func fibonacci() -> GeneratorFunc { enum State { case S0 case S1 } var state: State = .S0 func body() -> GeneratorFunc.ContinuationType { // Pretend we had Duff's device in Swift switch state { case S0: var (a, b) = (0, 1) while true { return GeneratorFunc.`yield`(b) { state = .S1; return body() } case S1: (a, b) = (b, a + b) } } } return GeneratorFunc.start(body) } This transformation is done by a late-stage SIL pass, which converts a SIL function containing special ``callcc`` instructions into the state machine or chained-closure representation. Doing the transformation in SIL keeps the frontend codegen for ``yield`` simple, and allows optimization passes to operate over the local state of the generator normally before it is obscured by the coroutine representation. Examples -------- GeneratorFunc ~~~~~~~~~~~~~~~~ The most obvious yieldable type is the generator function, which emits a sequence of the ``yield``-ed values from its body:: struct GeneratorFunc: Generator { typealias ContinuationType = (GeneratorFunc, T?) var _next: () -> ContinuationType static func start(entry: () -> ContinuationType) -> GeneratorFunc { return GeneratorFunc(entry) } static func `yield`(value: T, next: () -> ContinuationType) -> ContinuationType { return (GeneratorFunc(next), value) } static func `return`() -> ContinuationType { return (GeneratorFunc({ fatal("generator exhausted") }), nil) } mutating func next() -> T? { let (nextSelf, nextVal) = _next() self = nextSelf return nextVal } } An example:: func fibonacci() -> GeneratorFunc { var (a, b) = (0, 1) while true { yield b (a, b) = (b, a + b) } } // Print the Fibonacci sequence up to 1000 for x in fibonacci() { println(x) if x > 1000 { break } } SinkFunc ~~~~~~~~~~~ Sink functions, the duals to generators, can also be implemented as a yieldable type:: struct SinkFunc: Sink { typealias ContinuationType = SinkFunc var _next: (T -> SinkFunc)? static func start(entry: () -> SinkFunc) -> SinkFunc { return entry() } /// yield takes void and produces the next 'put' value static func `yield`((), next: T -> SinkFunc) -> SinkFunc { return SinkFunc(next) } static func `return`() -> SinkFunc { return SinkFunc(nil) } mutating func put(value: T) { if let next = _next { self = _next(value) } } } A sink function receives the next value ``put`` into the sink after every yield. This can be used to implement stateful event handlers:: enum MouseEvent { case MouseDown(time: Double) case MouseUp(time: Double) } // A sink that accepts click events and detects double-clicks. func senseDoubleClicks(clickDelay: Double, doubleClickDelay: Double, onDoubleClick: Double -> ()) -> Sink { while true { // Wait for the first mouse-down. var time: Double switch yield() { case .MouseDown(let t): time = t default: continue } // Wait for the first mouse-up. switch yield() { // Was it short enough to be considered a click? case .MouseUp(let t) where t - time < clickDelay: time = t default: continue } // Wait for the second mouse-down. switch yield() { // Was it soon enough to be considered a double-click? case .MouseDown(let t) where t - time < doubleClickDelay: time = t default: continue } // Wait for the second mouse-up. switch yield() { // Was it short enough to be considered a click? case .MouseUp(let t) where t - time < clickDelay: // Double-click successful! onDoubleClick(t) } } } let handler = senseDoubleClicks(clickDelay: 0.1, doubleClickDelay: 1.0, onDoubleClick: { println("double-click!") }) // Simulate an event sequence handler.put(.MouseDown(0.0)) handler.put(.MouseUp(0.05)) handler.put(.MouseDown(0.5)) handler.put(.MouseDown(0.55)) Monadic Control Flow ~~~~~~~~~~~~~~~~~~~~ For a monadic type, such as ``Optional`` or ``Error``, ``yield`` and ``return`` can map to the monadic "bind" and "return" concepts:: protocol Monad: Yieldable { // The monad operations: func bind(T -> Self) -> Self func mreturn(T) -> Self // Default implementation of Yieldable for a monad. typealias ReturnType = T typealias ContinuationType = Self class func start(entry: () -> Self) -> Self { return entry() } class func `yield`(value: Self, next: U -> Self) -> Self { return value.bind(next) } class func `return`(value: T) -> Self { return mreturn(value) } } This means that generators can be used as a shorthand for monadic control flow. For example, given an ``Error`` monad type defined thus:: enum Result: Monad { case OK(T) case Fail(Error) func bind(f: T -> Result) -> Result { switch self { case OK(let val): return f(val) case Fail: return self } } func return(x: T) { return OK(x) } } one can implement a "try" block using ``Result`` as a yieldable type:: // Try a computation that may produce an error. func try(block: () -> Result<(), Error>) -> Result<(), Error> { return block() } extension Result { // Handle an error. func catch(f: Error -> T) -> T { switch self { case OK(let val): return val case Fail(let err): return f(err) } } } try { // InputFile.open(String) -> Result let file = yield InputFile.open("/usr/share/dict/words") // InputFile.contents: Result let contents = yield file.contents for line in contents.lines { if line.endswith("gry") { println(line) } } }.catch { err in println("failed to read /usr/share/dict/words: \(err)") } The equivalent of C#'s ``async``/``await`` can also be implemented using monadic promise objects.