简体   繁体   中英

Haskell does not support the C++ overloading style in which functions with different types share a common name

I am learning Haskell. When I gone through following documentation. https://www.haskell.org/tutorial/classes.html

It is mentioned that "Haskell does not support the C++ overloading style in which functions with different types share a common name." I am not getting this statement, I guess ad-hoc polymorphism (which is done by using type classes) is equivalent to method overloading in C++, Java. Can some body explain me is my understanding correct ?

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

In the above snippet 'isEquals' function is applied to two different types Employee, Student which is equivalant of overloading in C++, Java. Is my understanding correct?

Partially, yes. However, keep in mind that signature of your isEquals is always a -> a . In C++ you could easily write:

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

By using typeclasses you're only able to get first and third function, never the second.

UPDATE 1:

as noted in comments, you can achieve the second version by using MultiParamTypeClasses extension (if you're using GHC). Still, there is fourth version:

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

which has wrong arity if you use a typeclass, but is perfectly fine in C++.

Type classes in Haskell are just a fancy way of providing implicit arguments. Consider this code:

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

What is the difference with your code? Well, if in your code we define

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

The difference is that in your code (with classes) compiler finds a suitable class instance by itself, using given types. In my variant, required instances are provided explicitly. But that's the only difference; in fact, your variant would be converted to mine under the hood.

So, classes do not override anything. They are just a fancy syntax for data types and implicit arguments.

Not really. The only way to get the equivalent of C++ (function; Haskell has no methods!) overloading would be a type class

class SomeFunc a where
    someFunc :: a

Now you can define someFunc at (more or less) any type you want. But you would have to declare it for every function you want to 'overload', whereas in C++ it's implicit simply from having two functions with the same name.

Haskell's type system is designed to provide something C++'s doesn't: standardized behavior (expressed as laws). So, for example, the standard Prelude defines

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

and now you know every == operator in the language takes two arguments, of the same type, and returns a boolean; by contrast, C++ is perfectly fine with something like

mystring operator (==)(mystring x, string y) {
    return x + " == " + y;
}

that breaks all of those 'reasonable' rules. Beyond that, type classes come with laws, eg

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

which are additional restrictions on all instances. That's made a lot easier by the fact that every instance is an instance of this type class (defined in one place), which gives you a single place to define what those laws are. In C++, such 'laws' have more of the character of conventions. Furthermore, C++ is explicitly designed to allow things like using + for string concatenation, while Haskell is explicitly designed to dis-allow things like that (that's what 'Haskell does not supporth the C++ overloading style' probably means), so laws have to have more of the character of conventions in C++, which individual types can ignore if it's convenient for them.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM