这就是我的困境:当编译Haskell程序时,会生成可在物理CPU上执行的二进制可执行机器代码.当解释Haskell程序时,物理CPU对来自内存位置的数据执行操作.执行实际上发生在一段时间内,其长度取决于CPU速度.
由于数据已经由编译器放入内存中,该编译器保证每个变量都是强类型的,这是否意味着Haskell实际上是否具有运行时类型?
澄清:"运行时类型"是指:在语言编译时语言编译器可访问/可识别的物理处理器上执行程序时变量的类型(在类型 - 理论意义上).
Ben*_*Ben 10
Haskell的语言功能旨在支持完整的类型擦除.这个想法是打字规则保证通过类型检查的代码具有以下两个属性1:
第二处房产继续扩张.显然,部分功能,如fromJust与head实际上并不处理任何可能的值; 如果给出错误的值,它们会在运行时爆炸.但在检查了他们所依赖的假设之后,他们以"定义明确"的方式爆炸.编写试图访问可能没有该子结构的值的子结构的代码是不可能的,这可能导致分段错误或解释随机内存片段,就像它们是不同类型的数据一样.
因此,在类型检查成功后,不需要在编译的程序中存储任何类型信息.我出租车只是把类型扔掉.我已经证明,如果我生成的代码盲目地对数据执行操作,假设它具有所需的形状,那么实际上什么都不会出错.
示例时间!
data Foo = Foo Int String
data Bar = Bar Int String
Run Code Online (Sandbox Code Playgroud)
Foo和Bar的值可能在内存中相同地表示为2 ; 一旦你知道所有值都是正确的类型,定义这些值所需的所有信息都是a Int和a String.如果您要查看正在运行的Haskell程序的内存转储,您将无法判断包含对a Int和a 的引用的给定内存对象String是a Foo还是a Bar(或者实际上是a (Int, String)或任何其他单个构造函数类型)两个字段是Int和String分别地).
所以不,Haskell类型在运行时不存在任何形式.
1您当然可以使用不安全的功能来破坏这些属性,例如unsafeCoerce:我在这里谈论的是"正常"的Haskell代码.
2或者他们可能没有.Haskell-the-language根本不保证运行时的表示,并且它完全有可能以不同的顺序存储字段,或者做一些可以区分两者的东西.但是我会假设在没有任何理由的情况下,它会将这两种类型视为相同.
任何编译程序中使用的"运行时类型" ,无论源语言如何,都是目标处理器本机支持的类型:通常是整数(有符号和无符号),指针(实际上只是整数的特殊用法),以及浮动 -点数(通常是IEEE754).编译器使用这些基本的硬件支持类型将源程序中的所有操作转换为等效的一系列操作.
更复杂的数据类型(例如Haskell列表)在运行时表示为从基本类型构建的数据结构.例如,列表中的每个节点可以由一对指针表示:一个指针由该节点保持的值(或用于计算它的thunk),一个指向下一个节点(或thunk).编译器的静态类型检查允许它确保每个运行时数据结构只能由能够正确处理它的代码访问.例如,保存列表节点的一对指针的内存区域不会被错误地视为用于计算整数的thunk,因为编译器仅允许将列表传递给期望列表参数的函数.
运行时类型信息通常在OOP语言实现中找到,它们带有每个对象的"类型标记".例如,拥有这样的信息可以编写诸如此类的代码
void foo(Object o) {
if (o instanceof SomeClass) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
这是一种运行时类型检查的形式."类型标记"通常是免费的,因为每个对象都需要一个指向虚方法表的指针,并且它只能识别对象的运行时类型.
但是,在Haskell中,不需要这样的标记,也不需要指向VMT的指针.该语言的设计没有任何类型的instanceof运算符,因此实现不必在运行时提供任何类型标记.这也导致了更好的基础理论,因为我们获得了代码的参数保证,也被称为"免费定理!".例如以下功能
f :: [a] -> [a]
f = .... -- whatever
Run Code Online (Sandbox Code Playgroud)
可以不被使实施f [1,2] = [2,3].这是因为,可证明,没有办法生产3了f.直觉是f必须产生一个a,并且它不能a=Int在运行时检查(没有类型标签),因此输出f只能包含在其输入中找到的元素.这种保证只来自上面的打字,甚至没有关心如何f实际实施.
如果你真的想要一个instanceof等价物,你可以使用Typeable它:
f :: Typeable a => [a] -> [a]
f [] = []
f (x:xs) = case cast x of
Just (y :: Int) -> [2,3]
Nothing -> x:x:xs
Run Code Online (Sandbox Code Playgroud)
[2,3]如果是整数,这将返回所有非空列表.在运行时,将传递类型标记,以便a=Int进行检查.