40关于Haskell和其他语言的评论设计问题

在很大程度上,我们发现哈斯克尔是一种令人愉快的语言使用,但我们有少量功能不太满意。我们将在下面进行讨论。

通过使用其他语言的经验,我们还意识到,一些语言功能目前还没有得到Haskell的支持会很有用。

40.1恼人的单态限制

当试图组合风格的程序,是单态限制。这意味着语法上不允许重载函数,除非提供了显式类型签名。

作为一个简单的例子,假设您要使用函数显示很多,想介绍一个更短的名字,说。由于单态限制,您不能编写

s=显示
有两种解决方案:可以提供类型签名

s::显示a=>a->Strings=显示
或者可以eta-expand定义

s x=显示x
在Fudget库中,我们使用了eta扩展技巧只要可能,因为包含了显式类型签名只要在更换图书馆时需要额外的维护工作。例如,当一个类型被重命名或一个函数被做得更多时通常,可能需要任意数量的类型签名已更新。

不幸的是,eta扩展技巧不能总是被使用,因为并非所有重载值都是函数。例如,软糖不是函数,所以如果您想引入的缩写显示F,您必须使用类型签名:

dF::(图形a)=>F a bdF=显示F
更不幸的是,有时这是不可能的表示类型签名。当定义为局部到另一个多态定义。这是可能发生的本地类型依赖于外部的类型变量定义,但Haskell没有表示此类类型的机制明确地。尽管这些案例在实践中非常罕见,这是语言的一个主要缺陷。

40.2 Haskell字符串+类系统异常

哈斯克尔的一个不雅之处是你无法直接生成类型字符串类的实例。这个这是由于两个事实的结合:这已经影响了类图解的ColorGen公司FontGen字体在中显示第二十七章、和表单元素在里面第29.2条。在开发时,我们通过定义一个数据类型来避免这个问题使用了而不是字符串,

新类型名称=名称字符串
但由于这需要使用建造师姓名在许多地方,我们后来也采取了同样的做法Haskell类使用的hack显示阅读即,我们添加了处理类列表的额外方法。这允许要在的实例声明中定义的字符串的方法烧焦.这意味着不需要为获取实例字符串,你获取的实例烧焦字符串[字符串][[字符串]]等等。对于我们的班级不难为额外实例:烧焦被视为单字符字符串。对于图解的类,通过绘制所有使用布局系统选择的布局的字符串。对于ColorGen公司FontGen字体classes,list被认为是备用的备选方案:你可以写,例如。,[“午夜蓝”,“黑色”]提供一种漂亮的颜色和一种安全的后备颜色。空列表可以给出运行时错误,但也可能导致键入问题(使过载无法解决)编译时。

40.3存在量化类型

现有量化类型[LO92系列]提供了一个非常好的语言特性,特别是与Haskell的类型结合使用类[Läu94公司]. 我们认为此功能应该具有很久以前就成为哈斯克尔标准的一部分。就现在而言,存在量化类型作为一种语言提供一些Haskell编译器的扩展(在编写时,仅限HBC[1997年8月](据我们所知)。

我们发现存在类型在以下几种情况下很有用:在Fudgets中实现小工具(第31章),面向句法操作的组合词(第28章)以及图形的数据类型(第27章).

由于存在类型不是Haskell标准的一部分,我们试图避免使用Fudget库。相反,我们在侧面使用它们来提供作为额外的奖励。这影响了我们使用它们的方式在图形数据类型中。例如,由于图纸的叶子通常是类型Gfx公司,我们可以用存在主义直接在中进行量化图纸类型,

数据图纸lbl=图形叶=>原子D叶|  ...
消除了对类型的需要Gfx公司。我们也可以定义了通用技术规范键入为

数据通用条款规范=(ColorGen c,FontGen f)=>SoftGC[GC属性c f]|硬GC GCtx
例如,允许您编写

SoftGC[GC前景“红色”]
而不是

SoftGC[GCForeground(colorSpec“红色”)]

40.4从属类型

Fudget库为标记并行提供了两个组合子fudgets的合成:二进制运算符>+<列表组合符列表F:

>+<::F类a b->F类c d->F类(要么a c)(要么b、d)列表F::(等式a)=>[(a,F类b c)]->F类(a、b)(a、c)
前者允许合成的软糖有不同的类型,但编写大量的fudget会使寻址个别软糖笨拙:使用施工人员左侧赖特.

后者使编写许多虚构的东西变得容易,但它们必须都有相同的类型。

使用依赖类型将允许我们定义一个组合符结合了>+<列表F.英寸类型理论[NPS90型],有两种形式的依赖类型:相依乘积(函数类型)和相依和(对)。第二种形式是我们这里需要的。它允许我们构造对,其中类型第二个组件的取决于价值第一个组件的。

使用类似Haskell的表示法,我们编写

(t吨::b t吨)
对于第一个组件为类型的对类型第二个组件的类型为b t吨,其中t吨第一个组件的值。请注意b是一个函数返回类型。

通过查看t吨作为标记,我们可以形成标记值的列表不同类型,并定义列表F使用以下类型:

d列表F::等式a=>[(t::a,F(it)(ot))]->F(t:,a,it)(t:;a,ot)