我正在学习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中的重载。我的理解是否正确?
答案 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 ++中约定的更多特性,如果方便的话,各个类型都可以忽略。