浅谈领域特定语言

  领域特定语言(domain-specific languages,简称DSL)

  在定义DSL是什么的问题上,Flowler认为目前经常使用的一些特征,例如“关注于领域”、“有限的表现”和“语言本质”是非常模糊的。因此,唯一能够确定DSL边界的方法是考虑“一门语言的一种特定用法”和“该语言的设计者或使用者的意图”:

  如果XSLT的设计者将其设计为XML的转换工具,那么我认为XSLT是一个DSL。如果一个用户使用DSL的目的是该DSL所要达到的目的,那么它一个DSL,但是如果有人以通用的方式来使用一个DSL,那么它(在这种用法下)就不再是一个DSL了。

  以Fowler的观点,DSL首先是一种帮助用户从一个系统中抽象出某些部分的工具。所以“当你意识到你需要一个组件,或者当你已经有了一个组件而你希望简化操作它的方式的时候”,DSL是有用的。使用DSL确实提供了某些益处。DSL不仅提高了代码的易读性,让开发者可以和领域专家更好的交流,而且是改变执行上下文的一种手段,例如:把逻辑从编译时切换到运行时,或者当命令式编程不是很合适的时候转用声明式计算模型。

  DSL包含哪些部分,有哪些分类

  DSL主要分为三类:外部DSL、内部DSL,以及语言工作台。

  外部DSL是一种“不同于应用系统主要使用语言”的语言。外部DSL通常采用自定义语法,不过选择其他语言的语法也很常见(XML就是一个常见选择)。宿主应用的代码会采用文本解析技术对使用外部DSL编写的脚本进行解析。一些小语言的传统UNIX就符合这种风格。可能经常会遇到的外部DSL的例子包括:正则表达式、SQL、Awk,以及像Struts和Hibernate这样的系统所使用的XML配置文件。

  内部DSL是一种通用语言的特定用法。用内部DSL写成的脚本是一段合法的程序,但是它具有特定的风格,而且只用到了语言的一部分特性,用于处理整个系统一个小方面的问题。用这种DSL写出的程序有一种自定义语言的风格,与其所使用的宿主语言有所区别。这方面最经典的例子是Lisp。Lisp程序员写程序就是创建和使用DSL。Ruby社区也形成了显著的DSL文化:许多Ruby库都呈现出DSL的风格。特别是,Ruby最著名的框架Rails,经常被认为是一套DSL。

  语言工作台是一个专用的IDE,用于定义和构建DSL。具体来说,语言工作台不仅用来确定DSL的语言结构,而且是人们编写DSL脚本的编辑环境。最终的脚本将编辑环境和语言本身紧密结合在一起。

  多年来,这三种风格分别发展了自己的社区。你会发现,那些非常擅长使用内部DSL的人,完全不了解如何构造外部DSL。我担心这可能会导致人们不能采用最适合的工具来解决问题。我曾与一个团队讨论过,他们采用了非常巧妙的内部DSL处理技巧来支持自定义语法,但我相信,如果他们使用外部DSL的话,问题会变得简单许多。但由于对如何构造外部DSL一无所知,他们别无选择。因此,在本书中,把内部DSL和外部DSL讲清楚对我来说格外重要,这样你就可以了解这些信息,做出适当的选择。(语言工作台稍显粗略,因为它们很新,尚在演化之中。)

  另一种看待DSL的方式是:把它看做一种处理抽象的方式。在软件开发中,我们经常会在不同的层面上建立抽象,并处理它们。建立抽象最常见的方式是实现一个程序库或框架。操纵框架最常见的方式是通过命令/查询式API调用。从这种角度来看,DSL就是这个程序库的前端,它提供了一种不同于命令/查询式API风格的操作方式。在这样的上下文中,程序库成了DSL的“语义模型”,因此,DSL经常伴随着程序库出现。事实上,我认为,对于构建良好的DSL 而言,语义模型是一个不可或缺的附属物。

  谈及DSL,人们很容易觉得构造DSL很难。实际上,通常是难在构造模型上,DSL只是位于其上的一层而已。虽然让DSL 工作良好需要花费一定的精力,但相对于构建底层模型,这一部分的付出要少多了。

  1. 我们常常会看到这样一种划分:一方面是程序库/框架或者组件的实现代码;另一方面是配置代码或组件组装代码。从本质上说,这种做法分开了公共代码和可变代码。用公共代码构建一套组件,然后根据不同的目的进行配置。

  2. “声明式”是一个非常模糊的术语,但是它通常适应于所有远离了命令式编程的方式。。。。远离变量倒换,用xml的子元素表示状态的动作和转换。

  3. DSL扮演领域专家和业务分析人员之间的交流媒介。。。

  4. 文本DSL有两种,称为外部DSL和内部DSL。外部DSL是指,在主程序设计语言之外,用一种单独的语言表示领域专用语言。内部DSL是指,用通用语言的语法表示的DSL;

  5. 是什么让内部DSL不同于通常的api呢?。。。连贯接口,这个术语强调这样一个事实:内部DSL实际只是某种形式的api,只不过其设计考虑了连贯性难以琢磨的质量。

  xx:后续在4.1节还会论述这个问题,DSL与api调用的区别,从这里看,两者都提供一种抽象,但DSL在抽象的设计上考虑了连贯性。

  在讲完以上内容后,提出DSL由三部分组成,即语言,语义模型和代码生成。语言只是用一种可读的方式来组装语义模型。

  6. 我强烈建议,几乎始终应该使用语义模型。。。。语义模型,清晰的将语言解析和结果语义的关注点切分开,。。。可以单独推究状态机的运作机制,增强和调试,无须估计语言。

  DSL只是模型一个薄薄的门面

  7.许多人用了代码生成之后,就舍弃了语义模型,他们在解析 输入文本之后,就直接产生生成的代码。。。不推荐任何人这么做。语义模型的存在,可以将解析,执行语义以及代码生成分开。

  最后推荐一个开发DSL的语言工作台,MetaEdit

技术专区

  • mybatis动态sql详解
  • 用VHDL语言设计数据传输系统中的HDB3编码器
  • 裸机程序如何驱动硬件?看前辈是怎么说的
  • 应用面向对象编程SoC原则的典型示例
  • 嵌入式开发之java常用开发工具介绍
  • 浅谈领域特定语言已关闭评论
    A+
发布日期:2019年07月14日  所属分类:物联网