Haskell不支持C ++重载样式,其中具有不同类型的函数共享一个公用名

时间:2016-04-14 14:33:01

标签: haskell

我正在学习Haskell。当我浏览以下文档时。 https://www.haskell.org/tutorial/classes.html

提到“Haskell不支持C ++重载样式,其中不同类型的函数共享一个通用名称。”我没有得到这个声明,我想ad-hoc多态(通过使用类型类完成)等同于C ++,Java中的方法重载。有些人可以解释一下我的理解是否正确?

class Equal a where

    isEquals :: a -> a -> Bool


type Id = Int
type Name = String

data Employee = Engineer Id Name 

data Student = Student Id Name

getEmpId (Engineer empId _) = empId
getStudId (Student studId _) = studId

instance Equal Employee where
    isEquals emp1 emp2 = getEmpId emp1 == getEmpId emp2

instance Equal Student where
    isEquals stud1 stud2 = getStudId stud1 == getStudId stud2

在上面的代码片段中,'isEquals'函数应用于两种不同类型的Employee,Student,它等同于C ++,Java中的重载。我的理解是否正确?

3 个答案:

答案 0 :(得分:2)

部分是的。不过请注意,isEquals的签名始终为a -> a。在C ++中,您可以轻松地编写:

int foo(int a, int b)
int foo(int a, char b)
int foo(char a, char b)

通过使用类型类,你只能得到第一个和第三个函数,而不是第二个函数。

更新1:

如评论中所述,您可以使用MultiParamTypeClasses扩展名来实现第二个版本(如果您使用的是GHC)。不过,还有第四个版本:

int foo(int a, int a, int a)

如果你使用类型类,它有错误的arity,但在C ++中完全没问题。

答案 1 :(得分:0)

Haskell中的类型类只是提供隐式参数的一种奇特方式。请考虑以下代码:

data Equal a = Equal {isEquals :: a -> a -> Bool}


type Id = Int
type Name = String

data Employee = Engineer Id Name 

data Student = Student Id Name

getEmpId (Engineer empId _) = empId
getStudId (Student studId _) = studId

equalEmployee :: Equal Employee
equalEmployee = Equal {
    isEquals = \emp1 emp2 -> getEmpId emp1 == getEmpId emp2
}

equalStudent :: Equal Student
equalStudent = Equal {
    isEquals stud1 stud2 = getStudId stud1 == getStudId stud2
}

equalThree :: Equal a -> a -> a -> a -> Bool
equalThree e a1 a2 a3 = isEquals e a1 a2 && isEquals e a2 a3

您的代码有什么区别?好吧,如果在你的代码中我们定义

equalThree :: Equal a => a -> a -> a -> Bool
equalThree a1 a2 a3 = isEquals a1 a2 && isEquals a2 a3

不同之处在于,在您的代码中(使用类),编译器会使用给定的类型自行查找合适的类实例。在我的变体中,显式提供了所需的实例。但这是唯一的区别;事实上,你的变种将在引擎盖下转换为我的。

因此,类不会覆盖任何内容。它们只是数据类型和隐式参数的奇特语法。

答案 2 :(得分:0)

不是真的。获得相当于C ++(函数; Haskell没有方法!)重载的唯一方法是类型类

class SomeFunc a where
    someFunc :: a

现在,您可以定义someFunc(或多或少)您想要的任何类型。但是你必须为你想要'重载'的每个函数声明它,而在C ++中它只是隐含了两个具有相同名称的函数。

Haskell的类型系统旨在提供C ++不具备的东西:标准化行为(表示为法律)。因此,例如,标准Prelude定义

class Eq a where
    (==), (/=) :: a -> a -> Bool

现在你知道语言中的每个==运算符都有两个相同类型的参数,并返回一个布尔值;相比之下,C ++完全没有像

这样的东西
mystring operator (==)(mystring x, string y) {
    return x + " == " + y;
}

打破了所有这些“合理”的规则。除此之外,类型类还有法律,例如

x == x = True -- x total
x == y = y == x
x == y = True => y == z = True => x == z = True

所有实例的附加限制。由于每个实例都是 this 类型的一个实例(在一个地方定义),这使得您只需一个地方来定义这些法则是什么,这使事情变得更加容易。在C ++中,这种“法则”具有更多的约定特征。此外,C ++被明确地设计为允许使用+来进行字符串连接,而Haskell明确地设计为不允许这样的事情(这就是'Haskell不支持C ++重载样式'可能意味着什么),所以法律必须要有C ++中约定的更多特性,如果方便的话,各个类型都可以忽略。