不是类型构造函数的类型级别函数的示例

时间:2018-08-25 22:38:40

标签: haskell type-level-computation

与其他类型级别的函数相比,Haskell中“类型构造函数”概念的独特之处是什么?

据我所知:

  • 允许用户在编译期间对其应用参数
  • 提供有限数量的参数后会产生简单类型(例如,不是约束)

1 个答案:

答案 0 :(得分:12)

短语“类型构造器”有两种常见用法。有些人将它们用于带有箭头的任何类型。但是Haskell报告以不同的方式一致地使用了它,因此我将讨论该定义。

构造函数由datanewtype声明创建,并且是这些声明在类型级别引入的单个新名称。以下是一些类型构造函数的示例:

Either
Maybe
[]
Bool

抱歉,您注意到最后一个吗?没错,“类型构造函数”一词并没有暗示它必须能够接受参数。 Bool是由数据声明引入的类型级别名称-因此是类型构造函数。以下是一些不是构造函数的类型的示例:

Maybe Int
a -> b
Either ()
m -- even if we know, say, Monad m holds

糟糕,您注意到最后两个吗?是的,朝着另一个方向发展,没有什么能够采用进一步的类型参数使您成为类型构造函数的了。 Either()都是构造函数,但是Either()的应用不是构造函数,因为它不是{{1 }}或data声明。同样,newtype是类型变量,而不是构造函数-它的含义不受任何mdata声明的约束。

除构造函数和变量外,标准Haskell中还有另一种类型级别名称:类型别名。类型别名和构造函数之间有两个主要区别:

  1. 构造函数是内射的,别名可能不是。如果newtypeFooC a b c是同一类型,并且FooC a' b' c'是构造函数,则FooCa是同一类型,a'b是同一类型,b'c是同一类型。对比

    c'

    其中type FooA a = String FooA ()是同一类型,即使FooA Bool()不是同一类型。

  2. 构造函数可能被部分应用,类型别名不能被应用。例如,如果您写

    Bool

    然后type BarA a = Maybe a 无效-即使StateT Int BarA ()仍然必须立即为BarA赋予其类型参数。当然,

    StateT Int Maybe ()

    然后type BarEtaA = Maybe 再次有效,因为别名StateT Int BarEtaA ()在扩展为定义的值BarEtaA之前不需要任何参数。

别名和构造函数之间还有一些其他细微的差别,但它们并不是基本的(并且通过适当的GHC扩展而得到了缓解)。

我可以在标准Haskell中想到的构造函数和变量之间只有一个区别,即它们与类型类机制的交互。具体来说,实例的格式必须为Maybe,约束/上下文的格式必须为instance <class> (<constructor> <variable> <variable> <variable> ...) where ...。通过适当的GHC扩展,可以放宽这些限制。

GHC实施的扩展Haskell还包括其他两种形式的已定义类型级别名称,即类型族和数据族,它们混合了上述某些属性。数据族定义的名称与构造函数非常相似(它们是可插入的,可以部分应用),而类型族定义的名称与别名非常相似(不能保证它们是单射的,不能部分应用)。主要区别在于它们可以执行“类型级模式匹配”,其中有多个定义适用于不同情况。完整的描述可能不适合StackOverflow的答案,但是the manual describes them以及指向讨论它们的多篇论文的链接。