新闻资讯
前端 DSL 实践指南——DSL 初识
和很多计算机领域的概念一样,DSL 其实也算是先有实践再有定义。
DSL 即「Domain Specific Language」,中文一般译为「领域特定语言」,在《领域特定语言》这本书中它有了一个定义:
一种为特定领域设计的,具有受限表达性的编程语言
编程语言的发展其实是一个不断抽象的过程,比如从机器语言到汇编语言然后到 C 或 Ruby 这类高级语言:
如上图所示,汇编语言通过助记符代替机器指令操作码,极大的增强了机器语言的可读性和可维护性。但本质上它仍是一门面向处理器和寄存器等硬件系统的低级编程语言。高级语言的出现解决了这个问题,真正脱离了对机器指令集的直接关联,以上层抽象的语句(流程控制、循环等)和数据结构等更趋近自然语言和数学公式的方式完成编码工作,大大提升了程序开发的效率。
但在高级语言层面,抽象带来的效率提升似乎有了天花板。无论是从 C 到 Java,抑或是各种编程范式下衍生的抽象度更高的编程语言,解决的都是通用编程问题,它们都有充分的过程抽象和数据抽象,导致大量的概念产生,进而影响了编程效率。
而在一些专有领域的任务处理上其实不需要那么多语言特性,DSL 就是在这种矛盾中产生的破局方案,它是为了解决特定任务的语言工具,比如文档编写有 markdown,字符串匹配有 RegExp,任务控制有 make、gradle,数据查找有 SQL,Web 样式编码有 CSS 等等。它的本质其实和我们很多软件工程问题的解决思路一样,通过限定问题域边界,从而锁定复杂度,提高编程效率。
我们先来个简单的例子,比如表示2周前的时间:
解法一
new Date(Date.now() - 1000 * 60 * 60 * 24 * 7 * 2);
解法二
2 weeks ago
解法三
(2).weeks().ago();
解法一是符合通用编程思维的解答,但即使作为程序员的我们也无法一眼看出其含义。
解法二和解法三其实就是 DSL 的两种不同类型——外部 DSL 和内部 DSL,它们的直观性显然更高(不信可以问问你的女朋友),但它却无法直接运行,假如你尝试在 JavaScript 环境下运行它,将会获得完全不同的错误:
- 2 weeks ago 会得到 Uncaught SyntaxError: Unexpected identifier 的语法错误。
- (2).weeks().ago() 则会得到一个 Uncaught TypeError: 2.weeks is not a function 的运行时类型错误。
其实从错误类型上我们就可以看到它们是有本质不同的。
外部 DSL 简述
解法二称之为外部 DSL ,它是一种独立的编程语言,需要从解析器开始实现自己的编译工具,实现成本较高。但它的语法的灵活性更高,更容易达到用户的表现力需求。
外部 DSL 的直接对应就是 GPPL,由于受限语法特性更少,一般不要求图灵完备,所以它实现难度会低于 GPPL。
GPPL 即 「General Purpose Programming Language」,又称通用编程语言,例如我们常用的 JavaScript,它们被设计用来解决通用编程问题。
前端常用的模板引擎如 mustache 以及 React、Vue 支持的 JSX 语法都属于外部 DSL。
mustache 的例子:
<h2>Names</h2> {{#names}} <strong>{{name}}</strong> {{/names}}
这可比手动拼装字符串高效多了。
内部 DSL 简述
解法三我们称之为 内部 DSL(Embedded DSL or Internal DSL) ,它是建立在其它宿主语言之上(一般为 GPPL)的特殊 DSL,它与宿主语言共享编译与调试工具等基础设施,学习成本更低,也更容易被集成。他在语法上与宿主语言同源,但在运行时上需要做额外的封装。
你也可以将内部DSL视为针对特定任务的特殊接口封装风格,比如 jQuery 就可以认为是针对 DOM 操作的一种内部 DSL。
内部 DSL 的语法灵活度和语法噪音(syntactic noise)往往取决于宿主语言的选择,本篇的例子我们会围绕 JavaScript 来展开。
syntactic noise is syntax within a programming language that makes the programming language more difficult to read and understand for humans.
简而言之:看着蛋疼,写着蛋疼。
最后我们来看下内部 DSL 以及外部 DSL 与一般通用语言 GPPL 的关系:
其中内部 DSL 的定义一直是社区辩论的焦点,为了理解内部 DSL 究竟是什么,我们先来熟悉下内部 DSL 的典型构建风格。
原文链接:https://segmentfault.com/a/1190000021791568
回复列表