Haskell中类型类的目的与Scala中traits的目的相对

时间:2014-09-21 06:57:28

标签: scala haskell typeclass traits

我试图理解如何考虑Haskell中的类型类与Scala中的特征。

我的理解是类型类在Haskell的编译时非常重要,而不再在运行时,另一方面,Scala中的特性在编译时和运行时都很重要。我想用一个简单的例子说明这个想法,我想知道我的观点是否正确。

首先,让我们考虑Haskell中的类型类

我们举一个简单的例子。类类Eq

例如,IntChar都是Eq的实例。因此,可以创建一个多态List,它也是Eq的一个实例,可以包含Int s或Char s,但不能同时包含在同一个List中。

我的问题是:这是Haskell 中存在类型类的唯一原因吗?

换句话说,同样的问题:

类型类可以创建多态类型(在此示例中为多态List),支持在给定类型类中定义的操作(在此示例中,类型类中定义的操作== { {1}})但根据我的理解,这是他们存在的唯一理由。我的这种理解是否正确?

(标准)Haskell中是否存在类型类的其他原因?

是否存在其他类型类在标准Haskell中有用的用例?我似乎无法找到任何。

由于Haskell的列表是同构的,因此无法将EqChar放入同一列表中。因此,根据我的理解,类型类的用处在编译时已经用完了。我的这种理解是否正确?

现在,让我们考虑Scala中类似的List示例:

让我们使用Int方法定义特征Eq。 现在让我们equalsChar实现特征Int

现在可以在Scala中创建一个Eq,将 List[Eq]Char接入相同列表(注意这一点 - 将不同类型的元素放入同一个List中 - 不可能是Haskell,至少在没有扩展的标准Haskell 98中是不可能的!)

在Haskell列表的情况下,根据我的理解,类型类的存在对于编译时的类型检查是重要的/有用的 非常重要。

相比之下,Scala中traits的存在对于类型检查在编译时是两者是重要的,并且在比较两个列表时对于List中对象的实际运行时类型的多态分派的运行类型是重要的为了平等。

所以,基于这个简单的例子,我来到结论,在Haskell类型类中,主要是在编译时使用/使用,相反,Scala的特性很重要/使用两者在编译时和运行时。

我的结论是否正确?

如果没有,为什么不呢?

编辑:

Scala代码回应n.m.的评论:

Int

打印:

case class MyInt(i:Int) {
  override def equals(b:Any)= i == b.asInstanceOf[MyInt].i
}

case class MyChar(c:Char) {
  override def equals(a:Any)= c==a.asInstanceOf[MyChar].c
}


object Test {
  def main(args: Array[String]) {
     val l1 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('b'))
     val l2 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('b'))
     val l3 = List(MyInt(1), MyInt(2), MyChar('a'), MyChar('c'))
     println(l1==l1)
     println(l1==l3)
  }
}

1 个答案:

答案 0 :(得分:9)

我将对Haskell方面发表评论。

类型类在Haskell中带来了受限多态性,其中类型变量a仍然可以被普遍量化,但仅在所有类型的子集上进行范围 - 即,类型为哪个类型类的实例可用。

为什么限制多态性有用?一个很好的例子是等于运算符

(==) :: ?????

它的类型应该是什么?直观地说,它需要两个相同类型的值并返回一个布尔值,所以:

(==) :: a -> a -> Bool         -- (1)

但上面的输入并不完全诚实,因为它允许将==应用于任何类型a,包括函数类型

(\x :: Integer -> x + x) == (\x :: Integer -> 2*x)

如果(1)(==)的输入,上面会传递类型检查,因为两个参数的类型都是a = (Integer -> Integer)。但是,我们无法有效地比较两个函数:众所周知的可计算性结果告诉我们,通常没有算法可以做到这一点。

那么,我们可以做些什么来实现(==)

选项1 :在运行时,如果发现函数(或任何其他涉及函数的值 - 例如函数列表)传递给(==),则引发例外。这就是例如ML确实如此。尽管在编译时检查类型,但现在键入的程序可能会出现错误"

选项2 :引入一种新的多态,将a限制为无函数类型。例如,ww可能有(==) :: forall-non-fun a. a -> a -> Bool,因此比较函数会产生类型错误。 Haskell利用类型类来获得那个。

因此,Haskell类型类允许用户输入(==)"老实说",确保在运行时没有错误,并且没有过度限制。当然,类型类的功能远不止于此,但至少在我看来,它们的主要目的是以非常通用和灵活的方式允许受限制的多态性。实际上,对于类型类,程序员可以定义自己对通用类型量化的限制。