在Haskell中删除类型?
我在阅读本段(http://www.seas.upenn.edu/~cis194/lectures/02-lists.html)时正在阅读关于Haskell的讲稿:
这种“不关心”是参数多态性中“参数化”的含义。 所有的Haskell函数都必须是参数类型参数; 基于这些参数的选择,功能不必关心或做出决定。 当a是一个函数时,函数不能做一件事,而当a是Bool时,函数不能做一件事。 Haskell根本没有提供写这种操作的工具。 这种语言属性称为参数性。
参数化有许多深刻和深刻的后果。 一种后果是所谓的类型擦除。 因为正在运行的Haskell程序不能根据类型信息做出决定,所以在编译期间可以删除所有的类型信息。 尽管编写Haskell代码时类型有多重要,但在运行Haskell代码时,它们完全不相关。 与Python等其他语言相比,此属性使Haskell获得了巨大的速度提升,它需要在运行时保持类型。 (类型擦除并不是使Haskell更快的唯一方法,但Haskell的有时钟速度比Python快20倍。)
我不明白的是“所有Haskell函数”是如何参数化的? Haskell中的类型是不是明确的/静态的? 另外我不太了解类型擦除如何提高编译时间运行时间?
很抱歉,如果这些问题真的很基础,我是Haskell的新手。
编辑:
还有一个问题:作者为什么说“尽管在编写Haskell代码时类型是多么重要,但在运行Haskell代码时却完全不相关”?
我不明白的是“所有Haskell函数”是如何参数化的?
它并没有说所有的Haskell函数都是参数化的,它说:
所有的Haskell函数都必须是参数类型参数 。
Haskell函数不需要任何类型参数。
还有一个问题:作者为什么说“尽管在编写Haskell代码时类型是多么重要,但在运行Haskell代码时却完全不相关”?
与动态类型语言不同,在运行时需要检查两个数字是否是数字,然后再将它们加在一起,运行的Haskell程序会知道,如果您尝试将它们加在一起,那么它们必须是数字因为编译器事先确定了它。
Haskell中的类型是不是明确的/静态的?
Haskell中的类型通常可以推断出来,在这种情况下,它们不需要明确。 但是你说得对,它们是静态的,这就是为什么它们在运行时不重要的原因,因为静态意味着编译器确保在你的程序执行之前所有东西都具有它应该使用的类型。
类型可以在Haskell中被删除,因为表达式的类型要么在编译时知道(如True
),要么类型在运行时不重要(比如[]
)。
有一点需要注意,它假定所有的值都有某种统一的表示。 大多数Haskell实现使用指针来表示所有内容,因此指针指向的实际类型并不重要(垃圾收集器除外),但您可以想象一个使用非均匀表示的Haskell实现,然后会生成一些类型信息必须保持。
其他人已经回答了,但也许有些例子可以提供帮助。
例如,Python直到运行时才保留类型信息:
>>> def f(x):
... if type(x)==type(0):
... return (x+1,x)
... else:
... return (x,x)
...
>>> f("hello")
('hello', 'hello')
>>> f(10)
(11, 10)
上面的函数,给定任何参数x
返回对(x,x)
,除非x
是int
类型。 该函数在运行时测试该类型,并且如果发现x
是一个int
它将以一种特殊的方式运行,返回(x+1, x)
。
为了实现上述,Python运行时必须跟踪类型。 那就是,当我们这样做时
>>> x = 5
Python不能将5
的字节表示存储在内存中。 它还需要使用类型标记int
来标记该表示,以便当我们type(x)
可以恢复标记。
此外,在执行任何操作(如x+1
Python需要检查类型标记以确保我们确实在处理int
。 如果x
例如是一个str
,Python将引发一个异常。
静态检查的语言(如Java)在运行时不需要进行此类检查。 例如,当我们跑步时
SomeClass x = new SomeClass(42);
x.foo();
编译器已经检查过,在编译时x
的确有一个方法foo
,所以不需要再做这个。 原则上这可以提高性能。 (实际上,JVM在类加载时会执行一些运行时检查,但为简单起见,我们忽略它们)
尽管如此,Java必须像Python一样存储类型标签,因为它具有类似于type(-)
:
if (x instanceof SomeClass) { ...
因此,Java允许编写可以在某些类型上“特别”表现的函数。
// this is a "generic" function, using a type parameter A
<A> A foo(A x) {
if (x instanceof B) { // B is some arbitrary class
B b = (B) x;
return (A) new B(b.get()+1);
} else {
return x;
}
}
上面的函数foo()
只是返回它的参数,除非它是类型B
,而是为其创建一个新对象。 这是使用instanceof
一个结果,它需要每个对象在运行时携带一个标签。
说实话,这样一个标签已经存在,可以实现虚拟方法,所以它不需要花费更多。 然而, instanceof
的存在使得在类型上导致上述非统一行为成为可能 - 某些类型可以被不同地处理。
Haskell,而不是这样的type/instanceof
操作符。 具有类型的参数Haskell函数
foo :: a -> (a,a)
必须在所有类型中以相同的方式行事。 没有办法引起一些“特殊”的行为。 具体来说, foo x
必须返回(x,x)
,我们可以通过查看上面的类型注释来看到这一点。 强调这一点,没有必要看代码(!!)来证明这种性质。 这是参数性从上面的类型确保的。