《领域特定语言》一1.4 语言和语义模型

1.4 语言和语义模型

在这个例子之初,我谈到了构建一个状态机模型。这种模型的存在,以及它同DSL的关系,是至关重要的。在这个例子里,DSL的角色就是组装状态机模型。因此,当解析定制语法的版本时,遇到:

events
 doorClosed D1CL

会创建一个新的事件对象(new Event("doorClosed","D1CL")),把它保存在一边(在一个 “符号表”(第14章)里),这样,遇到doorClosed=>active时,就可以将它包含在一个转换里(使用addTransition)。这个模型就是个引擎,它提供了状态机的行为。事实上,可以说,这个设计的能力大多源自这样一个模型。如图1-4所示,DSL所做的一切就是提供一种更可读的方式来组装这个模型─这就是与开始的命令查询API不同的地方。
从DSL的角度来看,我把这个模型称为“语义模型”(第11章)。谈及编程语言时,我们常常会提及语法(syntax)和语义(semantics)。语法描述程序的合法表达式,而在定制语法的DSL里所能描述的一切是由文法(grammar)决定的。程序的语义是指,它代表着什么,也就是说,当执行时,它能做什么。在这个例子里,模型定义了语义。如果你习惯使用Domain Model [Fowler PoEAA] ,这里就可以认为语义模型是与之非常类似的东西。

(你可以查看一下“语义模型”(第11章),了解一下语义模型同Domain Model之间的差异,还有语义模型和抽象语法树之间的不同。)
我有一个观点,对于一个设计良好的DSL而言,语义模型至关重要。在实际中,有的DSL用语义模型,而有些没有,但是我强烈建议,几乎始终(almost always)应该使用语义模型。(我发现,当说一些词比如“always”时,如果不加上限定词“almost”,几乎是不可能的。我几乎还没有找到一条广泛适用的规则。)
我提倡使用语义模型,因为它清晰地将语言解析和结果语义的关注点切分开。我可以推究出状态机的运作机制,对状态机进行增强和调试,而无须顾及语言问题。通过命令–查询接口,就可以组装状态机测试模型。状态机模型和DSL可以独立演进,即便还没想好如何通过语言表示,依然可以为模型添加新特性。也许,最关键的点在于,模型可以独立测试,而无须涉及语言。确实,上面所有DSL的例子都构建在相同语义模型上,基于这个模型,可以创建出完全相同的配置对象。
在这个例子里,语义模型是对象模型。语义模型还可以有其他形式。即便它只是一个纯粹的数据结构,所有的行为 都在单独的函数里,我依然愿意称之为语义模型,因为在那些函数的上下文里,数据结构表现出了DSL脚本特定的含义。
从这个角度来看,DSL只是扮演着展示模型配置机制的角色。使用这种方式的益处大多源自模型,而非DSL。为客户配置新的状态很容易,这是模型的属性,而非DSL。控制器可以在运行时改变,无须编译,这是模型的特性,而非DSL。可以在控制器的多次安装中重用代码,这是模型的属性,而非DSL。由此可见,DSL只是模型的一个薄薄的“门面”(facade)。
模型提供了诸多益处,与DSL如何表现无关。因此,我们一直使用它们。通过使用程序库和框架,我们可以明智地回避一些工作。在我们自己的软件里,构建模型,增进抽象,这样,就可以更快地开发。无论是作为程序库或者框架发布,或只是为自己的代码服务,即便没有任何可见的DSL,良好的模型都可以运作良好。
不过,DSL可以增强模型的能力。正确的DSL让我们更容易理解一个特定状态机的运作机制。一些DSL甚至可以让我们 在运行时配置模型。因此,DSL是对模型的一个有益补充。
DSL所带来的益处与状态机紧密相关,其所组成的某个特定模型就扮演了系统程序的角色。要改变状态机的行为,就需要修改模型中的对象及其相互关系。这种风格的模型通常称为“适应性模型”(第47章)。这样得到的是一个模糊了代码和数据之间差异的系统,只看代码,是无法理解状态机行为的,还必须了解对象实例的连接方式。当然,从某种程度上 说,这总是对的,任何程序对不同的数据都会给出不同的结果,但在此有个极大的差异,因为状态对象的存在会在很大程度上改变系统的行为。
适应性模型非常强大,但是通常也很难用,因为人们看不到任何定义特定行为的代码。DSL是有价值的,它提供了一种显式的方式表现代码,这种形式让人们对状态机编程有了感觉。
状态机可以很好地适用于适应性模型,原因在于,它是另一种计算模型。常规的编程语言提供了一种为机器编程的标准思考方式,多数情况下它运作良好。但是,有时,我们需要一些不同的方式,比如“状态机”(第51章),“产生式规则系统”(第50章),或者“依赖网络”(第49章)。使用适应性模型是一种好的方式,它提供了另一种计算模型,DSL则简化了为这种模型编程的方式。本书稍后会描述“其他一些计算模型”(第7章),在那里,你会了解到它们是什么样子,以及如何实现。或许你曾听说,有人把这种使用DSL的方式称为声明式编程。
在讨论这个例子时,我采用的流程是:首先构建模型,然后在此基础之上,用DSL封装出一个层次,对其进行操作。之所以用这种方式进行描述,是因为我觉得这是一种简单的方式,有助于理解DSL如何用于软件开发。虽然模型优先的情况很常见,但它并不是唯一方式。在不同的场景下,我们可能会与领域专家交谈,假定他们可以理解状态机方式。稍后,我们和他们一起工作,创建出他们可以理解的DSL。在这种情况下,DSL和模型可以同步构建。

时间: 2024-08-02 08:37:07

《领域特定语言》一1.4 语言和语义模型的相关文章

如何设计一门编程语言(十) 正则表达式与领域特定语言(DSL)

几个月前就一直有博友关心DSL的问题,于是我想一想,我在gac.codeplex.com里面也创建了一些DSL,于是今天就来说一说这个事情. 创建DSL恐怕是很多人第一次设计一门语言的经历,很少有人一开始上来就设计通用语言的.我自己第一次做这种事情是在高中写这个傻逼ARPG的时候了.当时做了一个超简单的脚本语言,长的就跟汇编差不多,虽然每一个指令都写成了调用函数的形态.虽然这个游戏需要脚本在剧情里面控制一些人物的走动什么的,但是所幸并不复杂,于是还是完成了任务.一眨眼10年过去了,现在在写Gac

《领域特定语言》一第1章 入 门 例 子1.1 哥特式建筑安全系统

第1章 入 门 例 子 落笔之初,我需要快速地解释一下本书的内容,就是解释什么是领域特定语言(Domain– Specific Language,DSL).为达此目的,我一般都会先展示一个具体的例子,随后再给出抽象的定义.因此,我会从一个例子开始,展示DSL可以采用的不同形式.在第2章里,我会试着把这个定义概括为一些更广泛适用的东西. 1.1 哥特式建筑安全系统 在我的童年记忆里,电视上播放的那些低劣的冒险电影是模糊却持久的.通常,这些电影的场景会安排某个古旧的城堡.密室或走廊在其中起着重要的作

《领域特定语言》一导读

前 言 在我开始编程之前,DSL(Domain–Specific Language,领域特定语言)就已经成了程序世界中的一员.随便找个UNIX或者Lisp老手问问,他一定会跟你滔滔不绝地谈起DSL是怎么成为他的镇宅之宝的,直到你被烦得痛不欲生为止.但即便这样,DSL却从未成为计算领域的一大亮点.大多数人都是从别人那里学到DSL,而且只学到了有限的几种技术. 我写这本书就是为了改变这个现状.我希望通过本书介绍的大量DSL技术,让你有足够的信息来做出决策:是否在工作中使用DSL,以及选择哪一种DSL

《领域特定语言》一第2章 使用DSL 2.1定义DSL

第2章 使用DSL 看过上一章的例子后,即便尚未给出DSL的一般定义,对于何为DSL,你也应该已经有了自己的认识.(第10章中有更多例子.)现在,要开始讨论DSL的定义及其优势与问题.这样就可以为下一章讨论DSL实现提供一些上下文. 2.1定义DSL "领域特定语言"是一个很有用的术语和概念,但其边界很模糊.一些东西很明显是DSL,但另一些可能会引发争议.这一术语由来已久,不过,正如软件行业中的很多东西一样,它也从未有过一个确切的定义.然而,就本书而言,定义是非常有价值的.领域特定语言

《领域特定语言》一2.2为何需要DSL

2.2为何需要DSL 至此,我希望,对什么是DSL,我们已经有了一个很好的共识,接下来的问题是,为何要考虑采用DSL.DSL只是一种工具,关注点有限,无法像面向对象编程或敏捷方法论那样,引发软件开发思考方式的深刻变革.相反,它是在特定条件下有专门用途的一种工具.一个普通的项目可能在多个地方采用了多种DSL─事实上很多项目这么做了.在1.4节中,一直强调,DSL只是模型的一个薄壳,这个模型可能是程序库,也可能是框架.这句话提醒我们,当考虑DSL的优劣时,一定要分清它是来自DSL的模型,还是DSL本

《领域特定语言》一3.3 文法、语法和语义

3.3 文法.语法和语义 如果要处理一种语言的语法,文法是一种很重要的工具.文法是一组规则,用以描述如何将文本流转化为语法树.大多数程序员都会在生命中的某一刻接触文法,因为文法常用以描述我们日常使用的程序设计语言.文法由一系列产生式规则组成,每个生产规则都有一个名字(term)以及一个描述如何分解它的语句(statement).所以,一个加法语句可能看起来就像这样: additionStatement:=number'+'number.它告诉我们,如果遇到语句5+3,解析器能够将其识别为加法语句

《领域特定语言》一1.5使用代码生成

1.5使用代码生成 在迄今为止的讨论中,要处理DSL,组装"语义模型"(第11章),然后执行语义模型,提供我们希望从控制器得到的行为.在语言圈子里,这种方式称为解释(interpretation).在解释文本时,会先解析文本,然后程序立刻产生结果.(在软件圈子里,解释是个棘手的词语,它承载了太多含义,然而,这里严格限制为立即执行的形式.)在语言领域里,与解释相对的是编译.在编译(compilation)时,先解析程序文本,产生中间输出,然后单独处理输出,提供预期行为.在DSL的上下文里

《领域特定语言》一2.6 设计优良的DSL从何而来

2.6 设计优良的DSL从何而来 审核本书的人常常问我,有没有一些"设计优良语言"的技巧.毕竟,语言设计很特别,我们不希望这个世界上充斥着糟糕的语言.我想分享一些好的建议,但我坦白,真没什么好办法.如同任何写作一样,DSL的总体目标就是对读者要清晰.我们希望本书的典型读者,可能是程序员,抑或是领域专家,能够尽可能快速清晰地理解DSL里句子的意图.虽然我觉得可能无法告诉你如何做到这一点,但是我的确觉得在工作中牢记这一点非常有价值.总的说来,我是迭代设计的粉丝,这次也不例外.尽早从目标受众

《领域特定语言》一第3章 实现DSL 3.1DSL处理之架构

第3章 实现DSL 至此,对于什么是DSL,以及为何要用DSL,我们已经透彻理解.如果要开始构建DSL,那么现在该深入研究所用的技术了.虽然构建内部DSL和外部DSL所用的技术有所不同,但它们还是有一些共通之处的.本章主要关注内部DSL和外部DSL的一些共通问题,而下一章再讨论各自具体的问题.本章先不谈语言工作台,留待后续探讨. 3.1DSL处理之架构 关于DSL实现的大体结构(见图3-1),也就是所谓的DSL系统架构─可能是我们要谈论的最重要的内容之一. 迄今为止,你应该已经厌倦了听我说了无数