星屑幻想-EDSL游记

星屑幻想-EDSL游记

题图P号:61560165

接下来,我打算写一系列关于EDSL的文章,这就充当EDSL的介绍吧。

什么是EDSL?

Embedded Domain Specific Language,是在某个编程语言(我们称之为MetaLanguage)中把一个DSL(我们叫之为ObjectLanguage)实现成库。我们用这个ObjectLanguage的主要方法,是写MetaLanguage的代码,并调用这个库,而不是写源代码,然后执行之。LINQ就是典型的EDSL。

EDSL的好处都有啥?谁说对了就给他!

既然这是个库,那么ObjectLanguage与MetaLanguage间的交互再简易不过-eval的结果可以是个richly-structured(换句话说不是string)MetaLanguage Term,增加一个新的Object Language primitive,就可以引入一个MetaLanguage的东西(更有甚者,直接支持一个叫embed的ObjLang primitive,这个节点引用一个MetaLang的值,就实现任意MetaLang -> ObjLang的交互了)

同时,这个语言就自动有宏了:这就是MetaLang中ObjLangAST(我们并不会引入MetaLang的AST,所以以后简称AST)到AST的函数。美中不足的是,你没有宏的宏(除非MetaLang也有宏),也丧失了同像性(所以,宏不能作用于自己)(again,除非MetaLang中也有同像性。从中你可以看出EDSL一个很大的特点:会继承MetaLang的各种属性,所以挑MetaLang很重要)

另一个好处:EDSL中,可以借用MetaLang的各种特性,去完成ObjLang的各种特性-比如最直接的:借用垃圾收集,closure,stack,laziness,compilation。。。也可以借用更高级的特性:parser, type checker/type class, type inference, debugger, binder等等。这是一把双刃剑:你借用的特性,往往会受MetaLanguage的限制(比如说,借用了type checking,你的类型系统就无法超越MetaLang的。当然,你可以放弃一部分的embedding,比如说,想要更强的type system就不借用MetaLang的type checking)

极强的可扩展性:由于ObjLang是MetaLang的某个概念,某些时候(Finally Tagless, Data Type A La Carte,或者Adapter)可以把两个ObjLang直接‘融合’在一起,组出新的语言!(并可以接着来更多的合体)同时,如果要写任何tool(如static analysis)无需经过parser/typechecker等,可以直接操作ObjLang在MetaLang中的representation (AST,Object,Graph)。(这点其实可以通过开放一定的API/Language Server做到,不过这样做的是少数。)

直接借用MetaLang生态:这个语言在方方面面都很像MetaLanguage,所以用MetaLang的人就更容易成为你的用户(并且想用也很简单,下个库就好,也更能读懂源代码知道是搞什么的)。也可以因为不存在交互障碍,直接用MetaLang的库当ObjLang的库,省去你写的功夫(如果是extensible的话,还可以让用户帮你加,岂不妙哉)当然,要借用生态圈,就得借用MetaLang的不小功能,你这语言就会受到MetaLang的很多限制。

⑨评EDSL-EDSL的各种属性:

  • 性能,类型系统,表达力-这些跟任意Language都是一样的属性就不提了
  • 是不是一阶的AST:可能因为通过借用binder,导致AST中有函数(Higher Order Abstract Syntax,简称HOAS)。一般来说,这样,你就无法pretty print,因为你无法看到函数的内部(当然,问题比打印不出来严重得多,比如说既然无法看到内部,就无法优化/分析里面的东西)
  • 挂钩度:什么特性是借用了MetaLang的。最常见的是挂钩binder(HOAS),挂钩type checker等等。
  • Internal Representation是不是well-typed/scoped的:你可不可能构造出这个语言的一个不具有意义的term?
  • 可扩展性:能否在不更改原有代码下(Meta Language的代码(原本的interpreter, debugger, static analyzer等),跟Object Language的(就是你的EDSL的程序)),加入新的EDSL的primitive/EDSL的mode(如compiler/pretty printer)?单独的完成这个并不难,难的是保证两边扩展性下,同时保证MetaLang的type safety(那些函数typecheck过了运行时就没错),modularity(以前的代码是封闭的)。
  • 当我们写一个语言的时候,我们就会同时给出这些属性的评测。

什么语言?

以后的文章,都会有具体代码,大体是:Haskell, Lisp, Smalltalk, Prolog等等。大家就一边看文章一边学新语言吧

文章被以下专栏收录
4 条评论
推荐阅读