代码之家  ›  专栏  ›  技术社区  ›  Roger Johansson

用自定义语言实现“生成器”支持

  •  3
  • Roger Johansson  · 技术社区  · 16 年前

    我对语言设计有一点迷恋,我现在正在玩弄我自己的语言爱好( http://rogeralsing.com/2010/04/14/playing-with-plastic/

    有一件事真的让我的心流血是“发电机”和“产量”关键字。

    有没有办法在没有AST转换的语言中获得生成器支持?

    1 回复  |  直到 16 年前
        1
  •  5
  •   Jörg W Mittag    16 年前

    生成器基本上是半协同的,有一些恼人的限制。因此,很明显,您可以使用半协程(当然还有完全协程)来实现它们。

    如果没有协程,则可以使用任何其他通用控制流构造。有很多控制流构造都是“通用的”,即 每一个 控制流构造(包括所有其他通用控制流构造),包括协程,因此生成器可以(或多或少)简单地转换为仅该通用构造。

    其中最著名的可能是 GOTO ,您可以构建 任何 IF-THEN-ELSE , WHILE FOR , REPEAT-UNTIL FOREACH

    几乎所有的CPU都支持 转到 (虽然在CPU中,他们通常称之为 jmp 转到 只有 控制流构造,尽管现在本机至少支持子例程调用( call

    另一个众所周知的控制流原语是continuations。延续基本上是一种更结构化、更易管理、更不邪恶的形式 转到 ,在函数语言中尤其流行。但是也有一些低级语言将它们的控制流建立在continuations的基础上,例如Parrot虚拟机使用continuations作为控制流,我相信在某些研究实验室里甚至有一些基于continuations的cpu。

    C有一种“蹩脚”的连续体形式( setjmp longjmp ),与“真正的”continuations相比,它们的功能要小得多,也不太容易使用,但是它们足够强大,可以实现生成器(事实上,可以用来实现完整的continuations)。

    setcontext 可以作为一个更强大和更高级别的替代品 设置JMP 长JMP .

    其他 上面的控制流构造是例外。有一篇论文表明,异常可能比连续性更强大,从而使异常在本质上等同于连续性 转到 因此具有普遍的力量。事实上,也有例外 有时用作通用控制流构造:MicrosoftVolta项目将.NET字节码编译为JavaScript,使用JavaScript异常实现.NET线程和生成器。

    不是通用的,但可能强大到足以实现生成器只是简单的尾部调用优化(不过,我可能错了。很不幸我没有证据。)我 可以将生成器转换为一组互尾递归函数。我知道状态机可以通过尾部调用来实现,所以我很确定生成器也可以,因为毕竟,C#将生成器实现为状态机(我认为这与懒惰的评估结合起来尤其有效。)

    最后但并非最不重要的一点是,在具有具体化调用堆栈的语言中(例如,像大多数Smalltalks),您可以构建几乎任何类型的控制流构造(事实上,具体化的调用堆栈基本上是过程性的低级别,相当于函数性的高级延续。)

    那么,什么 生成器的其他实现是什么样子的?

    Lua本身没有生成器,但是它有完全不对称的协程。主要的C实现使用 设置JMP 长JMP

    Ruby本身也没有生成器,但是它有 Enumerator s、 可以用作发电机。 枚举器 s不是语言的一部分,而是库的一个特性。MRI工具 枚举器 s使用continuations,而continuations又使用 设置JMP 长JMP . YARV机具 正在使用 Fiber 那些 使用实现 设置JMP 长JMP . 我相信JRuby目前实现了 枚举器 JVM正在使用线程,但是一旦JVM获得了一些更好的控制流结构,他们就希望切换到更好的结构。

    设置JMP / 长JMP

    推荐文章