尝试理解Haskell中的"=> "与定义类型的区别

7
在Haskell中,为什么要定义一个带有类型约束的函数:
ghci> :t (==)  
(==) :: (Eq a) => a -> a -> Bool

与其将其定义为类型为:

ghci> :t (==)  
(==) :: Eq -> Eq -> Bool

这两个语句不相等。 - Valentin Golev
2个回答

9

你不会使用第二个版本,因为你会得到一个编译错误。 Eq 不是一个类型,而是一个类型类。你不能在需要类型的地方使用类型类。

如果你定义了自己的类型 MyEq,然后定义一个类型为 MyEq -> MyEq -> Bool 的函数 ==,表达式 "hello" == "hello" 将是无效的,因为 "hello" 是 String 类型的值,而不是 MyEq 类型的值。由于 Haskell 中没有子类型,一个值不能同时是 String 类型和 MyEq 类型。

因此,如果你想定义一个可以接受满足特定条件的不同类型值的函数,你需要使用类型类。


1
继续上面的话题,可以在ghci中运行let a :: Eq -> Eq -> Bool ; a b c = b == c ; in a 2 2,查看所得到的错误。 - Aidan Cully
谢谢大家,这样就搞清楚了! - sneeu

7
在Haskell中,"类型"只能有一个特定的可能值集合,其不与任何其他类型重叠。 不存在一种类型是"不同种类的"或"子类型的"另一种类型。
当我们想要多态时,即可以适用于多种类型的函数,我们可以在函数的类型签名中使用类型变量来指定。 但是类型变量可以引用任何类型。我们并不总是知道如何为绝对每种类型定义我们的函数。例如,">" 函数仅适用于其元素可比较的类型。编译器将拒绝类型签名太普遍的函数,以帮助我们避免编写无意义的代码。
在您的示例中, "Eq" 不是一个类型。它是一个 "typeclass" - 一组类型的名称。我们使用 "class" 关键字声明类型类名称,并使用 "instance" 关键字将类型添加到类中。类型类的目的是用于约束,以限制类型变量的范围。
Haskell 的类型和多态性方法基于"Hindley-Milner"类型系统。这是一种非常精确但表达能力很强的描述数据的方式,使得编译器能够自动推断出程序中的各种类型,从而更容易地给出大量关于程序中类型的智能信息。该智能信息有助于编译器自动推断类型、在让您编写正确程序方面提供了很多帮助,并且优化编译结果,等等。
但是请注意 - 它与OOP中使用类型的方式非常不同,这可能是你习惯的方式。通常不存在OO程序和Haskell程序之间的直接转换。您必须从一开始就以不同的方式思考任务。特别要小心不要将Haskell的 "class" 和 "instance" 概念与完全不同的OOP中的这些单词的用法混淆。

与面向对象(OOP)中使用类型的方式非常不同,我不同意。Haskell 类型类真的像 OOP 中的“抽象类”或“接口”,我猜想一些虚函数表会随着参数一起传递到多态函数,以进行运行时调度。 - Alexandre C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接