INTERPRETER是反模式吗?

时间:2009-06-20 00:36:38

标签: design-patterns lisp anti-patterns interpreter-pattern greenspunning

对我而言,翻译模式听起来非常像一种被称为格林普森第十条规则的反模式:

  

任何足够复杂的C或Fortran程序都包含一个临时的,非正式指定的,错误缠身的,一半Common Lisp的慢速实现。

也就是说,如果你需要使用Interpreter,你可能会创建一些缓慢,临时和指定不当的东西。正确的解决方案是从一开始就使用正确的语言。

或者,或者,在您的应用程序中嵌入一个众所周知且语言清晰的语言,例如Guile(GNU可嵌入方案)。或者使用Haskell作为嵌入式域特定语言。

但我在实践中没有看到这一点 - 您在构建自己的嵌入式语言方面有哪些经验?这是个好主意吗?它比嵌入已有的语言更好吗?

(我不是特别喜欢lisp的粉丝。这很好,但是C和Haskell以及python和很多其他语言都是如此。)

10 个答案:

答案 0 :(得分:31)

解释器模式中没有任何内容表明它必须是您正在解释的另一种编程语言的语法。如果你需要解析一个简单的数学表达式,那么解释就是这个。

知道何时使用模式是阻止它成为反模式的原因。

答案 1 :(得分:14)

如果误用,任何设计模式都是反模式。

Interpreter Pattern的好用途:

  • 软件编译器
  • SQL评估引擎
  • 图形计算器输入解析器
  • XML解析器

这些都是解决评估语言中单词{,3}}的问题的程序。

答案 2 :(得分:8)

请记住,'解释器模式'是OOP中的特定设计模式。

它与“口译员”或其一般用途无关。

答案 3 :(得分:3)

在某些时候,项目可能需要一个配置系统。简单的东西通常是最初需要的东西,比如键值对,这样系统就可以连接到本地数据库,或者其他类似的东西。如果这就是所需要的,那么只需修改INI或CSV方言的简单解析器并继续前进即可。但随着系统的发展和成熟,配置也越来越重要。这是正常和健康的,重构功能和对正确抽象层的责任。从这里开始,开发人员甚至(喘息)用户都不会想要更具表现力的配置语言。在任何人注意到之前,系统都内置并使用了图灵完整语言。

这是Greenspunning的基本模式。一切都经过精心设计,最后一点,特殊语言被推入了真正的计算工作领域。

任何大小合适的系统应该至少包含一半的clisp。

提前知道这是一大步。编写大型系统的一种非常方便的方法是选择一种不错的,易于破解的解释语言并在其中编写系统。这恰好是TCL旨在做的事情,但是现在很难让任何人在这个语言的大项目背后。另一方面,有很多其他语言现在提供所有这些好处。

以这种方式做事的好处是Active File Pattern。简单配置的编写方式与系统可用的语言解析器兼容。由于该语言正在解析该文件,因此可以轻松嵌入更复杂的逻辑。

野外的一个例子是django的settings.py。出于某种原因,django对于猜测django项目的安装位置并不是很聪明。在配置文件中使用一些standard python,这可以在一般情况下以便携方式处理,几乎适合所有可能的用户。尽管如此,大多数settings.py文件看起来都像.ini样式配置文件中典型的普通旧键值对。

与解释器模式的关系是,即使是某些病理用途,这些成熟的语言也可能获得正确的模式。一旦你知道你需要解析一些东西,就会有一个很好的理由不使用现有的语言。

答案 4 :(得分:2)

解释器模式并不意味着编写完整的通用脚本语言。如果你需要它,显然使用一种众所周知的语言会更有意义,人们已经写过好书(或者最重要的是,允许用户选择语言)。

解释器模式更多地是关于持久化对象图的想法,而是选择一个人类可读和人类可编辑的持久性格式(例如2 + 3表示Addition对象,指针指向几个Integer个对象)。即使这从未作为“语言”暴露给客户,它仍然有助于调试,支持,现场黑客攻击等等。其他常见的例子是查询语言,例如[N] Hibernate中的HQL - 现有的语言在描述该抽象级别的查询时没有那么好。

正如其他人所建议的那样,XML通常被用作此基本语法(特别是在将持久化对象图构思为“配置文件”时,并且还参见Microsoft的XAML),但它实际上是次优选择。 UTF-8(或类似版本)中的JSON更干净,更易于解析,更易读和可编辑,因此对大多数应用程序来说可能更好。但是有一些很棒的轻量级解析器库,它们采用类似BNF的语法描述,然后可以在运行时将文本解析为类似DOM的可移动结构,因此编写一个高度特定的简洁语法是没有问题的。

答案 5 :(得分:0)

也许Lisp编译器的实现包含了一个Interpreter模式的例子。

我不认为你应该说“轮子”是一种反模式,即使你应该购买现成的轮子而不是重新发明它们。

答案 6 :(得分:0)

Interpreter是JavaCC解析器生成器背后的想法。我觉得它运作正常。

解释器是比Singleton更受尊重的GoF模式。这是需要在岛外投票的那个。也许是Memento。

答案 7 :(得分:0)

XML被发明的原因之一是让我们免于所有编写EDI的口译员;但至少范围是明确的,我们都大致平等(至少充分)有效地做到了。至少我仍然认为这是正确的做法。

听起来你正试图开创一个新的都市传奇?您是否先天反对域特定语言?

答案 8 :(得分:0)

你显然不是一个Lisp"粉丝",因为通常可以依赖那些符合该描述的男孩和女孩知道Lisp是一种编译语言。 Lisp出现于1958年。1961年的Lisp 1手册已经描述了编译。

口译很有用;它为我们提供了语义,而无需先编写编译器。这种语义为编译的语义提供了一个参考模型:理想情况下,解释和编译的程序可以做同样的事情。当我们发现他们没有,我们要么解决它,要么以某种方式描述和证明这种情况。

解释可用于引导已编译的Lisp系统而无需现有的Lisp实现,而是使用其他语言(如C语言)。解释避免了使用引导语言编写Lisp编译器的需要。

ANSI Common Lisp的CLISP实现就是一个很好的例子。要构建CLISP,您只需要一个C编译器。 CLISP的Lisp编译器是用Lisp编写的。所以,当然,你没有什么可以运行该编译器。解决方案是使用用C语言编写的解释器来解释编译器。

在运行解释时,编译器会编译很多Lisp库。这样做的结果就是CLISP称之为半编译的内存映像":一个包含已编译例程但仍有一些解释例程的映像。 (我认为,编译器本身仍然是解释代码)。

这个半编译的图像然后用于编译剩余的代码,从而产生完全编译的图像。

如果没有解释器,CLISP的编译器只能通过坚持首先安装另一个Lisp实现来引导。 (你需要一个C编译器来boostrap GCC的方式)。或者,CLISP的编译器必须用C编写,以便编译器使用现有的C编译器编译,然后应用于Lisp代码以便在运行之前对其进行编译。

没有正确的想法在C中编写Lisp编译器,并且要求Lisp实现构建Lisp实现在Lisp无处不在的世界中是一个很大的缺点。在Lisp-compiler-in-C boostrapping模型下会发生的事情是,用C语言编写的Lisp编译器将是一个完全最小的,可能是不完整的,它会发出质量差的代码,只能足以启动boostrapping,而且#34 ;实"编译器仍然用Lisp编写。

答案 9 :(得分:-1)

通常,编译器/解释器的各个阶段如下所示:

  1. 语法
  2. 解析树
  3. AST
  4. 编译或解释
  5. 在Lisp中,1和2合并为3。

    因此,显而易见的是,复杂的程序可能会嵌入一个自定义语言,即“一个临时的,非正式指定的,错误的,缓慢实现Common Lisp的一半”。

    但是我不得不说手写AST树是不愉快的,不管Lispers声称它有多少都不是最终的语言。