acm-headergydF4y2Ba
登录gydF4y2Ba

ACM通信gydF4y2Ba

实践gydF4y2Ba

使用Haskell的领域特定语言和代码合成gydF4y2Ba


使用Haskell的领域特定语言和代码合成,插图gydF4y2Ba

图片来源:Alicia Kubista / Andrij Borys AssociatesgydF4y2Ba

回到顶部gydF4y2Ba

给计算机下达指令的方法有很多种:电气工程师可以编写MATLAB程序;数据库管理员可能会编写SQL脚本;硬件工程师可能用Verilog编写;会计可能会写一个包含嵌入式公式的电子表格。除了在这些例子中使用的语言不同之外,还有一个重要的区别gydF4y2Ba形式gydF4y2Ba而且gydF4y2Ba成语gydF4y2Ba.每种方法都使用针对手头工作定制的语言,并且每种方法都以程序员熟悉且高效的形式构建计算请求(尽管会计人员可能不认为自己是程序员)。简而言之,每个示例都使用特定于领域的语言(DSL)。gydF4y2Ba

DSL是一种特殊用途的语言,被设计用来封装特定领域中可能的计算。在MATLAB、SQL、Verilog和电子表格的早期示例中,领域分别是科学建模、数据库查询和更新、硬件电路和金融计算。特别是考虑到SQL,它所做的一切都是Java或C或任何其他通用编程语言无法完成的。SQL只是简单地将与数据库交互所需的操作捆绑到一个可用的、高效的包中,并且该语言成为与数据库引擎通信请求的接口。gydF4y2Ba

dsl有两种基本类型。第一种是一级语言,如gydF4y2Ba图1 (1)gydF4y2Ba它有自己的编译器或解释器,经常在自己的生态系统中使用。到目前为止提到的所有例子都属于这一类。例如,SQL DSL和Java之间的主要区别是范围和焦点,尽管有时DSL会发展到与通用语言一样大。gydF4y2Ba

另一类DSL是嵌入在宿主语言中的语言,如所示gydF4y2Ba图1 (2)gydF4y2Ba.这样的语言可以有自己的语言的外观和感觉,但它们利用宿主语言的现有生态系统和初始语义。本文讨论的是第二类dsl。gydF4y2Ba

回到顶部gydF4y2Ba

Haskell底漆gydF4y2Ba

嵌入式DSL (EDSL)是一种语言中的语言。Haskell,gydF4y2Ba17gydF4y2Ba最重要的纯函数式编程语言,是EDSLs的一个很好的宿主,因为它具有灵活的重载、强大的类型系统和惰性语义。本节简要介绍Haskell,足以使本文独立。它是我2011年在可重构系统和算法工程国际会议上发表的Haskell入门教程的扩展版本。gydF4y2Ba10gydF4y2Ba

Haskell的一切gydF4y2Ba类型gydF4y2Ba.与其他语言中的类型一样,Haskell中的类型是结构值的限制性摘要。例如,在Haskell中gydF4y2Ba保龄球gydF4y2Ba是值的类型吗gydF4y2Ba真正的gydF4y2Ba而且gydF4y2Ba虚假的;IntgydF4y2Ba是机器大小的字的类型;gydF4y2Ba双gydF4y2Ba为双精度IEEE浮点值类型;C、c++、Java和其他传统语言也是如此。Haskell中的所有这些类型名都以大写字母开头。gydF4y2Ba

在这些基本类型之上,Haskell有两种表示复合类型的语法形式。首先,可以使用元语法、圆括号内逗号分隔的类型来编写对、三元组和更大的结构。因此,(gydF4y2BaInt,保龄球gydF4y2Ba)是一个有an的结构gydF4y2BaIntgydF4y2Ba和一个gydF4y2Ba保龄球gydF4y2Ba组件。其次,列表有一个语法快捷方式,使用方括号。因此,gydF4y2Ba(Int)gydF4y2Ba是一个列表gydF4y2BaIntgydF4y2Ba.gydF4y2Ba

Haskell还有其他容器类型。一个容器gydF4y2Ba五月gydF4y2Ba包含一个gydF4y2BaIntgydF4y2Ba有类型gydF4y2Ba也许IntgydF4y2Ba,阅读gydF4y2Ba也许是IntgydF4y2Ba.这些容器名也以大写字母开头。gydF4y2Ba

类型可以嵌套到任何深度。例如,你可以有一个gydF4y2Ba((可能(Int, Bool)))gydF4y2Ba,读作gydF4y2BaMaybe of的列表(Int和Bool)gydF4y2Ba.gydF4y2Ba

多态值使用小写字母表示,其作用类似于C中的void*指针和Java泛型工具中的多态参数。这些多态值可以使用相当于对象层次结构的Haskell表达式来表示约束。gydF4y2Ba

最后,使用从参数类型到结果类型的箭头来编写函数。因此,在Haskell中,接受一个列表并返回一个列表的函数被写成:gydF4y2Ba[a] -> [a]gydF4y2Ba.gydF4y2Ba

下面是一个Haskell函数的例子:gydF4y2Ba

ins01.gifgydF4y2Ba

这个函数使用快速排序的变体对列表进行排序,其中主元是列表的第一个元素:gydF4y2Ba

  • 第一行是for的类型gydF4y2Ba排序gydF4y2Ba.这是gydF4y2Ba∀一gydF4y2Ba,以致于gydF4y2Ba一个gydF4y2Ba可以排序(允许像<=这样的比较);函数接受并返回一个此类列表gydF4y2Ba一个gydF4y2Ba的年代。gydF4y2Ba
  • 第二行表示空列表已经排序。gydF4y2Ba
  • 其余的行表示,可以通过取列表的第一个和其余部分(称为gydF4y2BaxgydF4y2Ba而且gydF4y2BaxsgydF4y2Ba,分别),对这个主元之前和这个主元之后的值进行排序,并将这些中间值连接在一起。gydF4y2Ba
  • 方法来命名中间值gydF4y2Ba在哪里gydF4y2Ba语法;的值gydF4y2Ba之前gydF4y2Ba而且gydF4y2Ba后gydF4y2Ba.gydF4y2Ba

Haskell是一种简洁直接的语言。Haskell中的结构是用类型表示的,有构造的也有解构的,但从不更新。例如,gydF4y2Ba也许gydF4y2Ba类型可以使用两个构造函数定义,gydF4y2Ba没有什么gydF4y2Ba而且gydF4y2Ba只是gydF4y2Ba:gydF4y2Ba

ins02.gifgydF4y2Ba

没有什么gydF4y2Ba是一个gydF4y2Ba也许gydF4y2Ba的东西;gydF4y2Ba只是gydF4y2Ba,带着论点,是一个gydF4y2Ba也许gydF4y2Ba参数的类型。这些构造函数可以用来构造和解构结构,但从来没有任何更新;Haskell中的所有结构都是不可变的。gydF4y2Ba

使用基于类的重载系统,可以赋予特定类型额外的功能,例如相等和比较。的gydF4y2Ba也许gydF4y2Ba例如,Type可以通过一个实例来测试是否相等:gydF4y2Ba

ins03.gifgydF4y2Ba

这说明,对于任何可以测试是否相等的类型,您也可以进行检查gydF4y2Ba也许gydF4y2Ba同类型的。你拿着gydF4y2Ba也许gydF4y2Ba分开,使用模式匹配上gydF4y2Ba只是gydF4y2Ba,检查内部值。gydF4y2Ba

在Haskell中,诸如向屏幕写入或读取键盘之类的副作用使用gydF4y2Ba做gydF4y2Ba符号:gydF4y2Ba

ins04.gifgydF4y2Ba

在这个例子中gydF4y2Ba价值gydF4y2Ba被称为gydF4y2Ba主要gydF4y2Ba使用gydF4y2Ba做gydF4y2Ba描述与用户交互的符号。实际上,gydF4y2Ba做gydF4y2Ba-notation将其捕获为一个叫做a的结构gydF4y2Ba单孢体;gydF4y2Ba纯洁是不妥协的。更详细的信息是关于如何gydF4y2Ba做gydF4y2Ba-notation和monads可以在纯语言(如Haskell)中提供有效的接口。gydF4y2Ba18gydF4y2Ba就本文而言,gydF4y2Ba做gydF4y2Ba-notation是一种提供看起来像交互的语法和结构的方法。关于Haskell有很多教程;Haskell网站,(gydF4y2Bahttp://haskell.orggydF4y2Ba)是进一步阅读的一个很好的起点。gydF4y2Ba

回到顶部gydF4y2Ba

嵌入式dslgydF4y2Ba

EDSL是宿主语言中的库,具有自身语言的外观、感觉和语义,并针对特定的问题域进行定制。通过重用宿主语言的工具和工具,EDSL大大降低了开发和维护DSL的成本。得益于Haskell简洁的语法,Haskell社区和函数式编程社区普遍采用了EDSLs的思想,并开发了大量dsl,这些dsl为易于理解的系统提供了更高级别的接口和抽象。下面是EDSLs的两个示例:一个用于为软件测试自动生成测试用例;第二种用于指定硬件电路行为。gydF4y2Ba

示例EDSL: QuickCheck属性gydF4y2Ba.考虑编写测试用例的挑战——或者更具体地说,编写gydF4y2Ba属性gydF4y2Ba测试用例需要满足:gydF4y2Ba

ins05.gifgydF4y2Ba

在这个例子中,gydF4y2Baprop_reverse_twicegydF4y2Ba是一个常规的Haskell函数,它接受gydF4y2BaIntgydF4y2Ba并根据所提出内容的有效性返回一个布尔值——具体地说,两个反向内容相互抵消。下面是最巧妙的部分:gydF4y2Baprop_reverse_twicegydF4y2Ba是gydF4y2Ba也gydF4y2Ba特定于领域的语句,因此可以被视为Haskell中的子语言。这种使用函数的风格(在本例中,函数名的前缀是gydF4y2Baprop_gydF4y2Ba,接受许多类型化参数,并返回一个条件)是一种小型语言。用Haskell编写的属性也是属性的EDSL,称为QuickCheck。gydF4y2Ba4gydF4y2Ba这个EDSL可以使用一个也称为EDSL的函数运行gydF4y2BaquickCheck:gydF4y2Ba

ins06.gifgydF4y2Ba

通过运行gydF4y2BaquickCheckgydF4y2Ba有了这个显式的和特定的属性,EDSL在Haskell内部执行。的gydF4y2BaquickCheckgydF4y2Ba函数为属性生成100个测试用例,并动态执行它们。如果它们都保持,那么系统将打印一条反映这一点的消息。测试用例是使用类型类系统生成的,quickcheck为特定类型提供了生成测试用例的能力gydF4y2BaquickCheckgydF4y2Ba函数使用它来生成随机测试。gydF4y2Ba

作为一个不正确的属性示例,考虑for的这个属性gydF4y2Ba反向gydF4y2Ba.gydF4y2Ba

ins07.gifgydF4y2Ba

这说明两个截然不同的列表的反向与两个附加在一起的列表的反向相同,但该属性为false。gydF4y2Ba

ins08.gifgydF4y2Ba

事实证明,这种迷你语言在实践中是非常有用的。尽管使用Haskell的方式很简单,但是QuickCheck EDSL提供了一种思考和直接表示属性的方法。它还有额外的功能,包括生成随机函数参数的能力,控制随机测试用例的分布的能力,以及声明属性的前提条件的能力。从这个DSL中,已经构建了这些想法的许多其他实现。甚至有一家瑞典公司QuviQ,为并发编程语言Erlang销售QuickCheck。gydF4y2Ba

示例EDSL: Kansas LavagydF4y2Ba.再举一个例子,考虑描述硬件。硬件描述语言和函数式语言长期以来一直有着卓有成效的合作关系。Lava是一个Haskell dsl的名字,它实现了硬件描述语言Ruby的基于函数的版本。gydF4y2Ba12gydF4y2Ba,gydF4y2Ba13gydF4y2Ba不要与同名的现代编程语言混淆,Ruby是基于关系的,而关系的灵感又来自于gydF4y2BaμgydF4y2Ba《外交政策》。gydF4y2Ba21gydF4y2Ba

堪萨斯州的熔岩gydF4y2Ba11gydF4y2Ba是一个haskell托管的DSL,它遵循了Lava的研究路线。它是一种表示门级电路的语言。Haskell抽象允许程序员在稍高的抽象级别上工作,其中模型是通过同步流进行通信的递归组件之一。Kansas Lava已经被用于遥测解码器的高性能电路的生成,尽管所使用的模型是通用的。gydF4y2Ba

以《Kansas Lava》为例gydF4y2Ba图2gydF4y2Ba这个电路连接两个多路复用器gydF4y2Ba(mux2)gydF4y2Ba一只蝰蛇和一只gydF4y2Ba注册gydF4y2Ba给出一种计算信号上已计时脉冲数的电路gydF4y2Ba公司gydF4y2Ba.电路接受两个时钟信号并返回一个时钟信号,该信号显式地使用相同的时钟操作,因为它们共享相同的类型。算术的使用是低调的,但是简单地使用(通过重载)标准的加法语法;的gydF4y2Ba全国矿工工会gydF4y2BaConstraint允许这样做。gydF4y2Ba图3gydF4y2Ba说明了用于此描述的电路。gydF4y2Ba

你可以像调用组合函数一样直接地模拟顺序电路(参见gydF4y2Ba图4gydF4y2Ba).gydF4y2Ba

除了基本的信号类型,您还可以构建直接作用于Haskell函数的电路,前提是函数的域是有限的。的gydF4y2Ba代表gydF4y2Ba功能用于表示可以枚举类型中所有可能的可表示值gydF4y2BafunMapgydF4y2Ba功能:gydF4y2Ba

ins09.gifgydF4y2Ba

生成的电路是使用ROM实现的,您可以直接根据Haskell函数和数据结构生成控制逻辑。例如,考虑一个存储值平方的小ROM:gydF4y2Ba

ins10.gifgydF4y2Ba

通过这种方式,直接的Haskell函数可以提升到gydF4y2Ba信号gydF4y2Ba世界。注意如何gydF4y2BasquareROMgydF4y2Ba函数没有特定的大小,而是完全泛型的,只要求参数流的类型可以表示为数字。gydF4y2Ba

时钟平方ROM现在可以用于特定类型。例如,在8位时,你可以生成以下内容:gydF4y2Ba

ins11.gifgydF4y2Ba

这种级别的电路规范已经在许多Lava和类似Lava的语言中得到了很好的应用。一个著名的例子是霍克,gydF4y2Ba15gydF4y2Ba一种类似lava的EDSL,用于指定奔腾Pro的整个微架构,包括超级标量设计和寄存器旁路功能。gydF4y2Ba

现在,如果dsl作为库设计的习惯用法如此强大,那么为什么它们还没有接管呢?作为一种表达事物的方式gydF4y2Ba模拟gydF4y2Ba, EDSLs是一种无价的设计模式;然而,并不是所有东西都是模拟的。如果您想使用EDSL来表示希望在其他地方(而不是在Haskell系统中)运行的内容,该怎么办?Lava能被用来生成运行在fpga(现场可编程门阵列)上的电路吗?EDSLs可以用来为嵌入式处理器或gpu生成代码吗?这种综合外部解决方案的能力将非常有用。EDSL习惯用法可以被扩展以实现这一点,但有一些重要的注意事项。本文的其余部分将讨论如何从EDSL内部捕获和导出工作,该功能可以用于什么,以及有哪些限制。gydF4y2Ba

回到顶部gydF4y2Ba

深度嵌入的领域特定语言gydF4y2Ba

EDSLs只是考虑所提供函数库的一种方式,通常称为gydF4y2Ba组合子gydF4y2Ba,因为它们将它们的参数合并到DSL中的术语中。在前面的Lava示例中,gydF4y2Ba注册gydF4y2BaCombinator接受一个初始值和一个传入的值流,并提供一个被单个周期延迟的新流,初始值占据初始周期。关键的是,gydF4y2Ba注册gydF4y2Ba是组成;它将DSL的较小部分结合起来,形成更大的解决方案。如果DSL在设计上仔细遵循这种可组合性,那么就有可能实现另一种重要的实现。gydF4y2Ba

EDSL最常见的风格是使用所谓的浅嵌入,如gydF4y2Ba图1 (2)gydF4y2Ba,其中值直接计算。浅EDSL中的计算结果是一个值。到目前为止,所有的例子都很肤浅。然而,还有另一类EDSLs:特别是那些使用深度嵌入构建抽象语法树的EDSLs,如gydF4y2Ba图1 (2 b)gydF4y2Ba.在深度嵌入的DSL(深度EDSL)中,计算的结果是一个结构,而不是一个值,这个结构可以用于计算值或在计算之前进行交叉编译。gydF4y2Ba7gydF4y2Ba这种深度EDSLs在设计和命令上迂腐地遵循可组合性的咒语。gydF4y2Ba

从历史上看,EDSLs一直很肤浅——只是一种为库构造API的方法。然而,深度EDSLs有能力gydF4y2Ba阶段gydF4y2Ba代码——也就是说,执行一个程序可以生成另一个程序,这与众所周知的YACC DSL非常相似,但代价是显著限制了可以生成有效输出的DSL的形式。深度EDSLs的数量越来越多,围绕其形式和局限性的研究也越来越多。统一的主题是,深度EDSLs可以是实用的、高效的和有用的。gydF4y2Ba

本节将比较深度EDSL和浅EDSL的基本结构,并研究提高深度EDSL有用性的三个实用技巧。gydF4y2Ba

构建一个深度EDSLgydF4y2Ba.一个深度嵌入的DSL暴露了它自己的组成和结构。深度DSL不是使用直接对值操作的函数(浅DSL),而是构建一个结构,然后允许一些辅助代理提供对该结构的解释。为了使这个想法具体化,考虑一个算术DSL,包括加减乘和常数。对于一个浅嵌入,运行这个DSL是微不足道的;你只需要使用内置的算术。深度嵌入是事情变得有趣的地方。考虑我们的算术数据类型:gydF4y2Ba

ins12.gifgydF4y2Ba

现在重载算术来使用这个Expr数据类型;在Haskell中,gydF4y2Ba全国矿工工会gydF4y2Ba是积分运算的重载:gydF4y2Ba

ins13.gifgydF4y2Ba

通过构建Expr类型的表达式,你可以观察到计算的结构:gydF4y2Ba

ins14.gifgydF4y2Ba

这是深刻的,也是使深度嵌入工作的关键思想。您可以编写一个表达式并提取一个树gydF4y2Ba什么gydF4y2Ba要做,没有直接的结果。在深度嵌入中,通常还需要编写一个run函数来计算捕获计算的结果:gydF4y2Ba

ins15.gifgydF4y2Ba

图5gydF4y2Ba说明了浅dsl和深dsl之间的区别,以及深度嵌入与特定运行函数如何结合得到相同的结果。对于深度嵌入的DSL, run函数恢复了浅嵌入的功能,但另一个函数采用了嵌入式结构,并以某种创造性的方式使用它。gydF4y2Ba

为了使深度DSL变得实用,在DSL民间传说中有两个几乎总是被使用的额外技巧。第一个技巧允许通过虚拟参数捕获函数。第二种方法是通过某种形式的可观察共享来观察循环。gydF4y2Ba

如何从函数中提取深度嵌入gydF4y2Ba.用构造函数和构建表达式树来表示函数调用是有用的,但它本身就是一种噱头。但是,通过仔细的构造,您还可以直接从深层嵌入捕获函数定义以及其他语法结构。此时,捕获代码,然后使用捕获的代码在不同的目标上执行代码的想法成为可能。考虑一个简单的函数将1添加到它的参数中:gydF4y2Ba

ins16.gifgydF4y2Ba

下面是一个作用于新类型的函数gydF4y2BaExprgydF4y2Ba并返回一个新的gydF4y2BaExprgydF4y2Ba.如何捕获这个函数?诀窍在于发明一种独特的gydF4y2BaExprgydF4y2Ba并将其作为(虚拟)参数传递给gydF4y2BafgydF4y2Ba:gydF4y2Ba

ins17.gifgydF4y2Ba

您现在可以直接运行该函数并在深度嵌入中查看结果,或者传入gydF4y2BaVargydF4y2Ba参数并查看实际的函数gydF4y2Ba图6gydF4y2Ba:这太了不起了!您已经运行了一个带有虚拟参数(称为gydF4y2Ba典型的观点gydF4y2Ba),提取函数体。gydF4y2Ba

这个想法可以扩展到多参数函数。考虑gydF4y2BaggydF4y2Ba:gydF4y2Ba

ins18.gifgydF4y2Ba

的两个原型参数gydF4y2BaggydF4y2Ba将捕获函数:gydF4y2Ba

ins19.gifgydF4y2Ba

可以在许多地方使用此设计模式。一个例子是将表面纹理指定为函数;可以将这些输出到gpu上的可执行代码中,同时提升用于编写纹理的抽象,并加快相同操作的执行速度。这里没有任何关于Haskell或函数式语言的特定内容。实际上,相同的思想已经在Java中用于VHSIC硬件描述语言(VHDL)生成器。gydF4y2Ba2gydF4y2BaHaskell具有强大的抽象功能,它让深度dsl几乎感觉像是简单的浅嵌入。gydF4y2Ba

如何发现循环gydF4y2Ba.熔岩程序被编写成递归绑定的方程。直接建造熔岩的深度嵌入将导致结构的无限循环。为了说明这一挑战,让我们构建一个深度嵌入的Lava,看看哪里出了问题,并使用一种称为可观察共享的技术进行修复。gydF4y2Ba

首先,Lava语言需要一个结构。在gydF4y2Ba图7gydF4y2Ba,我们定义了以前使用过的函数,但对它们进行了深层的嵌入,称为gydF4y2Ba信号gydF4y2Ba.gydF4y2Ba

输出树是无限的。所发生的情况是,递归定义在试图具体化函数,或者更具体地说,具体化的主体时展开gydF4y2Ba计数器gydF4y2Ba是循环的。在这一点上,EDSL社区受到阻碍。有人尝试使用单元结构,其中循环用gydF4y2Ba做gydF4y2Ba符号,gydF4y2Ba8gydF4y2Ba使循环成为可观察的效果。有一个不安全的扩展,通过绕过Haskell的纯粹性来观察有限形式的共享,称为可观察共享。gydF4y2Ba5gydF4y2BaHaskell I/O机制还有一个扩展,它允许间接观察循环,称为基于I/ based可观察共享。gydF4y2Ba9gydF4y2Ba这三种机制的最终效果是,观察到的树被渲染为具有命名边的图。gydF4y2Ba

在这一点上,Haskell将我们从一些复杂性中解救出来。高级类型系统机制,例如高级类型参数,允许结构是树或图,这取决于类型级别的实例化。这里省略细节,具体化的函数是具有共享的树,然后转换为具有显式共享的图。这个示例实体的最终结果gydF4y2Ba计数器gydF4y2Ba是:gydF4y2Ba

ins20.gifgydF4y2Ba

在此输出中,每个大写构造函数都对应于其深层嵌入的构造函数。快速检查显示电路已捕获,如图所示gydF4y2Ba图3gydF4y2Ba.从这个网列表风格的结构中,生成VHDL是很简单的。对于四位数字的例子,提供了VHDLgydF4y2Ba图8gydF4y2Ba.gydF4y2Ba

这两个技巧(原型参数和基于I/ based可观察共享)是Kansas Lava的技术基础。在这个基础上,在Haskell类型系统的帮助下,一个完整的电路生成生态系统已经开发出来。DSL习惯用法允许程序员在Haskell中使用高级抽象并生成有效的电路。然而,并非一切都是美好的;由于深度嵌入的局限性,编写Lava程序与编写Haskell程序是不同的。gydF4y2Ba

回到顶部gydF4y2Ba

深度嵌入只是程序的一半gydF4y2Ba

深度EDSL的基础是建设性的基础。函数式编程是关于构造的gydF4y2Ba和解构gydF4y2Ba值。因此,深度嵌入不能具体化任何模式匹配,甚至不能直接使用if-then-else -和其他控制流。堪萨斯熔岩公司避开了这个问题——例如,它使用了gydF4y2Bamux2gydF4y2Ba构造函数,它对选择进行编码。如果你需要解构,这个习语还能推进到什么程度?结果令人惊讶。让我们从这三种能力开始:gydF4y2Ba

  • 基本表达式可以通过构建与您的语法类似的树来捕获。gydF4y2Ba
  • 可以使用假唯一参数捕获函数。gydF4y2Ba
  • 可以使用某种形式的可观察共享来观察局部绑定。gydF4y2Ba

这三种能力自动产生了第四个能力:gydF4y2Ba

  • 宿主语言为嵌入式语言提供了一个内置宏功能。Haskell的任何部分(包括控制流和模式匹配)都可以用于gydF4y2Ba生成gydF4y2Ba嵌入式语言。gydF4y2Ba

对基本技术也有扩展。主要有:gydF4y2Ba

  • 内部函数调用可以被捕获为图上的节点,而不是直接内联。gydF4y2Ba14gydF4y2Ba这有助于大型程序的编译,提供了基本的独立编译功能。gydF4y2Ba
  • 的gydF4y2Ba做gydF4y2Ba语句可以通过归一化来具体化。gydF4y2Ba16gydF4y2Ba,gydF4y2Ba19gydF4y2Ba,gydF4y2Ba22gydF4y2Ba这个结果叫做gydF4y2Ba单细胞生物的具体化gydF4y2Ba,令人惊讶。有充分的技术理由相信单矢物化是不可能的;然而,规范化重构了那些不可能单独解决的约束,并将它们一对一地匹配起来,使用匹配的证人,从而实现整体gydF4y2Ba做gydF4y2Ba-符号需要解决和具体化。一元物化是最近才发现的,但已经在一些深度dsl中得到了应用,包括FeldspargydF4y2Ba1gydF4y2Ba和天窗。gydF4y2Ba3.gydF4y2Ba
  • 控制流是有问题的,不能直接使用,但是Haskell布尔的一般化确实允许深度嵌入捕获。gydF4y2Ba6gydF4y2Ba使用这个库,可以构造具有控制流的DSL,但它需要是在DSL级别上使用构造函数的显式代码。的gydF4y2Bamux2gydF4y2Ba前面使用的函数是这种思想的简化。这种用法虽然笨拙,但可行,我们应该能够做得更好。gydF4y2Ba

这将深度dsl置于何处?对于语言实现者来说,它们显然是一种有用的设计模式,但它们也有成本和局限性。因此,我们如何推动技术的发展,让更多的Haskell语言具体化呢?它有两个主要缺点。我们已经讨论过的一个问题是:控制流和模式匹配仍然是dsl中的一根刺。gydF4y2Ba

参数多态性是函数式程序的优点之一,也是深度dsl的另一个问题。需要一个特定的结构来表示已捕获的内容,而任意的多态性都会干扰这一点。当前的系统通过始终在特定类型上实例化来回避这个问题,但这是昂贵的,因为捕获的程序的大小可以呈指数级扩展。多态是人们认为单一物化不可能的技术原因,但在那种情况下,它被标准化所回避;该技术并不适用于所有的多态性。gydF4y2Ba

深度DSL是提取表达式的值级方法,但是还有其他方法。准引用是一种提取表达式的机制,但是是在语法级别上。Haskell附带了一个广泛的模板系统,称为template HaskellgydF4y2Ba20.gydF4y2Ba,通常用于领域特定语言。人们对这种解决方案感到不安;然而,以几乎相同的方式使用C预处理器,尽管它被认为并不优雅。主要问题是Haskell的语法非常庞大,包含大约100个语法术语。基于表达式的解决方案,例如深度嵌入,可以避免重写前端翻译的需要。准引用有一个重要的优点:具体来说,它可以应对控制流和价值的解构。也许深度dsl的未来是表达式生成和准引用之间的某种混合,结合了这两种系统的优点。gydF4y2Ba

回到顶部gydF4y2Ba

致谢gydF4y2Ba

本文基于美国国家科学基金会资助的工作。CCF-1117569,最初是2013年11月苏格兰信息学和计算机科学联盟访问学者计划下的一个硕士班。堪萨斯熔岩的例子和描述改编自作者之前写的一篇关于熔岩的文章。gydF4y2Ba10gydF4y2Ba

ACM队列的q戳gydF4y2Ba相关文章gydF4y2Ba
在gydF4y2Baqueue.acm.orggydF4y2Ba

群众的OCamlgydF4y2Ba
Yaron明斯基gydF4y2Ba
http://queue.acm.org/detail.cfm?id=2038036gydF4y2Ba

LINQ的世界gydF4y2Ba
埃里克·梅耶尔gydF4y2Ba
http://queue.acm.org/detail.cfm?id=2024658gydF4y2Ba

不熟悉的DSLgydF4y2Ba
Debasish GhoshgydF4y2Ba
http://queue.acm.org/detail.cfm?id=198975gydF4y2Ba

回到顶部gydF4y2Ba

参考文献gydF4y2Ba

1.Axelsson, E., Claessen, K., Sheeran, M., Svenningsson, J., Engdal, D.和Persson, A.数字信号处理嵌入式语言Feldspar的设计和实现。在gydF4y2Ba二十二届会议的会议记录gydF4y2BandgydF4y2Ba函数式语言实现与应用国际会议gydF4y2Ba.中国科学(d辑),2011,41 - 46。gydF4y2Ba

2.Bellows, P. and Hutchings, B. jhdl -可重构系统的HDL。gydF4y2BaIEEE现场可编程自定义计算机年度研讨会gydF4y2Ba(1998)。gydF4y2Ba

3.Bracker J.和Gill A. Sunroof:用于生成JavaScript的单体DSL。gydF4y2Ba声明性语言的实践方面gydF4y2Ba.M. Flatt和H-F Guo,编。gydF4y2Ba计算机科学课堂讲稿8324gydF4y2Ba.国际出版,2014,65-80。gydF4y2Ba

4.Quickcheck:用于随机测试Haskell程序的轻量级工具。在gydF4y2Ba五人会议记录gydF4y2BathgydF4y2BaACM SIGPLAN函数式编程国际会议gydF4y2Ba(2000), 268 - 279。gydF4y2Ba

5.Claessen, K.和Sands, D.功能电路描述的可观察对象共享。在gydF4y2Ba亚洲计算机科学会议论文集,计算机科学讲稿gydF4y2Ba.Verlag, 1999年。gydF4y2Ba

6.艾略特,C.布尔包;gydF4y2Bahackage.haskell.orggydF4y2Ba.gydF4y2Ba

7.编译嵌入式语言。gydF4y2Ba函数式程序设计学报gydF4y2Ba, 2(2003)。gydF4y2Ba

8.Erkök, L.和Launchbury, J.递归一元绑定。在gydF4y2Ba五人会议记录gydF4y2BathgydF4y2BaACM SIGPLAN函数式编程国际会议gydF4y2Ba(2000), 174 - 185。gydF4y2Ba

9.Haskell中类型安全的可观察对象共享。在gydF4y2Ba2号会议记录gydF4y2BandgydF4y2BaACM SIGPLAN Haskell研讨会gydF4y2Ba(2009), 117 - 128。gydF4y2Ba

10.使用Kansas Lava的声明式FPGA电路合成。gydF4y2Ba可重构系统与算法工程国际会议gydF4y2Ba(2011)。gydF4y2Ba

11.Gill, A., Bull, T., Farmer, A., kimmel, G.和Komp, E.硬件模拟和合成的类型和相关类型族:堪萨斯熔岩的内部和外部。gydF4y2Ba高阶和符号计算gydF4y2Ba,(2013), 1-20。gydF4y2Ba

12.Ruby解释器。gydF4y2Ba研究报告72gydF4y2Ba,(1993)。查尔默斯理工大学。gydF4y2Ba

13.Jones, G.和Sheeran, M. Ruby的电路设计。gydF4y2BaVLSI设计的形式化方法gydF4y2Ba.Jorgen Staunstrup,主编,爱思唯尔科学出版社,1990年。gydF4y2Ba

14.Mainland, G.和Morrisett, G. Nikola:在Haskell中嵌入编译过的GPU函数。在gydF4y2Ba会议记录gydF4y2Ba理查德·道金斯gydF4y2BaACM Haskell专题讨论会gydF4y2Ba(2010), 67-78。gydF4y2Ba

15.马修斯,库克,B.和Launchbury, J.霍克中的微处理器规范。在gydF4y2Ba计算机语言国际会议论文集gydF4y2Ba(1998), 90 - 101。gydF4y2Ba

16.Persson, A., Axelsson, E.和Svenningsson, J.嵌入式语言的泛型单体结构。gydF4y2Ba函数式语言的实现与应用gydF4y2Ba, 2012, 85-99。施普林格。gydF4y2Ba

17.佩顿·琼斯,s.l.,编辑。gydF4y2BaHaskell 98语言和库-修订报告gydF4y2Ba.剑桥大学出版社,2003。gydF4y2Ba

18.Peyton Jones, S.L.和Wadler, P.命令式函数编程。在gydF4y2Ba20国会议记录gydF4y2BathgydF4y2BaACM SIGPLAN-SIGACT编程语言原理研讨会gydF4y2Ba,(1993), 71-84。gydF4y2Ba

19.斯库索普,布拉克,乔吉兹,G.和吉尔,A.单子约束问题。在gydF4y2Ba十八人会议记录gydF4y2BathgydF4y2BaACM SIGPLAN函数式编程国际会议gydF4y2Ba,(2013), 287-298。gydF4y2Ba

20.Haskell的模板元编程。gydF4y2BaACM SIGPLAN Haskell研讨会02gydF4y2Ba.M.M.T.查克拉瓦蒂主编,ACM出版社,2002年10月,1-16。gydF4y2Ba

21.μFP, VLSI设计语言。在gydF4y2BaACM LISP和函数式编程研讨会论文集gydF4y2Ba,(1984), 104-112。gydF4y2Ba

22.单元嵌入式语言的简单和组合具体化。在gydF4y2Ba函数式程序设计国际会议论文集gydF4y2Ba,(2013), 299-304。gydF4y2Ba

回到顶部gydF4y2Ba

作者gydF4y2Ba

安迪·吉尔gydF4y2Ba(gydF4y2Baandygill@ku.edugydF4y2Ba他是堪萨斯大学电子工程与计算机科学系的助理教授。gydF4y2Ba

回到顶部gydF4y2Ba

数据gydF4y2Ba

F1gydF4y2Ba图1。领域特定语言的类型。gydF4y2Ba

F2gydF4y2Ba图2。堪萨斯熔岩的一个柜台。gydF4y2Ba

F3gydF4y2Ba图3。堪萨斯熔岩奇偶计数器示意图。gydF4y2Ba

F4gydF4y2Ba图4。运行堪萨斯熔岩作为模拟。gydF4y2Ba

F5gydF4y2Ba图5。算术的浅嵌入和深嵌入。gydF4y2Ba

F6gydF4y2Ba图6。捕获函数的结构。gydF4y2Ba

F7gydF4y2Ba图7。熔岩的深度嵌入。gydF4y2Ba

F8gydF4y2Ba图8。VHDL生成的堪萨斯熔岩计数器。gydF4y2Ba

回到顶部gydF4y2Ba


版权归所有者/作者所有。gydF4y2Ba

数字图书馆是由计算机协会出版的。版权所有©2014 ACM, Inc.gydF4y2Ba


没有找到条目gydF4y2Ba

登录gydF4y2Ba全面访问gydF4y2Ba
忘记密码?gydF4y2Ba »创建ACM Web帐号gydF4y2Ba
文章内容:gydF4y2Ba
Baidu
map