2.25. 生成器

生成器允许您声明一个行为类似于迭代器的 lambda。 对于所有意图和目的,生成器是传递给 eacheach_ref 函数的 lambda。

生成器语法类似于 lambda 语法:

generator ::= `generator` < type > $ ( ) block

生成器 lambda 必须没有参数。它始终返回布尔值:

let gen <- generator<int>() <| $ {  // gen is iterator<int>
    for ( t in range(0,10) ) {
        yield t
    }
    return false                    // 返回 false 停止迭代
}

generator 表达式的结果类型是一个迭代器 (参阅 Iterators).

生成器通过 yield 表达式输出迭代器值。 与 return 语句类似,允许移动语义 yield <-

return <- generator<TT> () <| $ {
    for ( w in src ) {
        yield <- invoke(blk,w)  // 移动调用结果
    }
    return false
}

生成器可以输出 ref 类型。他们可以有一个 capture 部分:

unsafe {                                                // 由于通过引用捕获 src 而不安全
    var src = [1,2,3,4]
    var gen <- generator<int&> capture(ref(src)) () <| $ {      // 通过 ref 捕获 src
        for ( w in src ) {
            yield w                                     // yield of int&
        }
        return false
    }
    for ( t in gen ) {
        t ++
    }
    print("src = {src}\n")  // will output [[2;3;4;5]]
}

生成器可以具有 Loop 和其他控制结构:

let gen <- generator<int>() <| $ {
    var t = 0
    while ( t < 100 ) {
        if ( t == 10 ) {
            break
        }
        yield t ++
    }
    return false
}

let gen <- generator<int>() <| $ {
    for ( t in range(0,100) ) {
        if ( t >= 10 ) {
            continue
        }
        yield t
    }
    return false
}

生成器可以在其块上有一个 finally 表达式,但 if-then-else 块除外:

let gen <- generator<int>() <| $ {
    for ( t in range(0,9) ) {
        yield t
    } finally {
        yield 9
    }
    return false
}

2.25.1. 实现细节

在以下示例中:

var gen <- generator<int> () <| $ {
    for ( x in range(0,10) ) {
        if ( (x & 1)==0 ) {
            yield x
        }
    }
    return false
}

生成包含所有捕获变量的 lambda:

struct _lambda_thismodule_8_8_1 {
    __lambda : function<(__this:_lambda_thismodule_8_8_1;_yield_8:int&):bool const> = @@_::_lambda_thismodule_8_8_1`function
    __finalize : function<(__this:_lambda_thismodule_8_8_1? -const):void> = @@_::_lambda_thismodule_8_8_1`finalizer
    __yield : int
    _loop_at_8 : bool
    x : int // captured constant
    _pvar_0_at_8 : void?
    _source_0_at_8 : iterator<int>
}

生成 lambda 函数:

[GENERATOR]
def _lambda_thismodule_8_8_1`function ( var __this:_lambda_thismodule_8_8_1; var _yield_8:int& ) : bool const {
    goto __this.__yield
    label 0:
    __this._loop_at_8 = true
    __this._source_0_at_8 <- __::builtin`each(range(0,10))
    memzero(__this.x)
    __this._pvar_0_at_8 = reinterpret<void?> addr(__this.x)
    __this._loop_at_8 &&= _builtin_iterator_first(__this._source_0_at_8,__this._pvar_0_at_8,__context__)
    label 3: /*begin for at line 8*/
    if ( !__this._loop_at_8 ) {
            goto label 5
    }
    if ( !((__this.x & 1) == 0) ) {
            goto label 2
    }
    _yield_8 = __this.x
    __this.__yield = 1
    return /*yield*/ true
    label 1: /*yield at line 10*/
    label 2: /*end if at line 9*/
    label 4: /*continue for at line 8*/
    __this._loop_at_8 &&= _builtin_iterator_next(__this._source_0_at_8,__this._pvar_0_at_8,__context__)
    goto label 3
    label 5: /*end for at line 8*/
    _builtin_iterator_close(__this._source_0_at_8,__this._pvar_0_at_8,__context__)
    return false
}

控制流语句被 label + goto 等价物替换。 生成器总是以 goto __this.yield 开头。 这有效地产生了一个有限状态机,其中 yield 变量保存当前状态索引。

yield 表达式将转换为复制结果和返回值对。 创建一个标签来指定下次在 yield 之后去哪里:

_yield_8 = __this.x                 // produce next iterator value
__this.__yield = 1                  // label to go to next (1)
return /*yield*/ true               // return true to indicate, that iterator produced a value
label 1: /*yield at line 10*/       // next label marker (1)

迭代器初始化将替换为 lambda 的创建:

var gen:iterator<int> <- each(new<lambda<(_yield_8:int&):bool const>> default<_lambda_thismodule_8_8_1>)