我一直在查找haskell的核心语言,以了解它是如何工作的。我在互联网搜索过程中发现的一个功能是类型强制。我知道他们习惯于实施GADT,但我不了解其他的东西。我在网上找到的所有描述对我来说都是相当高的水平,尽管我对系统F有一个很好的理解。请问有人能以一种可以理解的方式向我解释强制类型吗?
答案 0 :(得分:4)
基本上Haskell通过评估这种简单的核心语言来编译。为了保持简单,通常不希望将诸如GADT之类的构造或直接类型类添加到语言中,因此它们在编译器的最前端被编译成更简单但更通用(并且更详细) )核心提供的构造。还要记住Core是键入的,所以我们必须确保我们能够以类型化的方式对所有这些事情进行编码,这是一个非常复杂的问题。
为了对GADT进行编码,它们被精心设计为具有存在和强制的普通数据类型。基本思想是强制是一种所谓的平等类型,写成t ~ t'
。这个类型旨在见证证据,即使我们可能不知道它,t
和t'
也是同一类型。它们像任何其他类型一样传递,因此处理方式没有什么特别之处。还有一套用于操纵这些类型的类型构造函数构成了关于相等性的小证据,例如sym :: t ~ t' -> t' ~ t
。最后,在术语级别有一个运算符,它使用t
类型的术语和类型t ~ t'
的类型,并键入t'
类型的术语。例如cast e T :: t'
但这个术语与e
的行为相同。我们刚刚使用了t'
和t
相同的证据来投射e
以使类型检查器满意。
这是基本的想法
cast
在术语级别使用这些证明另请注意,通过将证明隔离到类型级别,它们最终不会产生运行时成本,因为类型将被删除。
我认为所有这些都是System F with Type Equality Coercions的一个很好的参考,但当然所有SPJ的出版物都可以提供帮助。
答案 1 :(得分:2)
@jozefg值得回答,但这里是GADT的一个例子,他们不顾一切存在量化。还不是Core,但迈出了一步。
data Foo :: * -> * where
Bar :: Int -> Foo Int
Oink :: b -> c -> d -> Foo (f b)
经由
data Foo a where
Bar :: (a ~ Int) => Int -> Foo a
Oink :: (a ~ f b) => b -> c -> d -> Foo a
到
data Foo a
= (a ~ Int) => Bar Int
| forall b c d f. (a ~ f b) => Oink b c d