When shall I define polymorphic functions by type classes or by some other ways?

207 Views Asked by At

I am trying to figure out the purpose of type class, and what else is there if not using type class.

Is type class a way to define polymorphic functions?

Is type class the only way to define polymorphic functions? For example:

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

instance Eq Bool where 
    False == False  =  True 
    True  == True   =  True 
    _     == _      =  False

Can I define == and /= for Bool (and any other type) without using type class Eq?

Where there is any other way, when shall I use which way to define polymorphic functions, by using type class or by using the other way?

3

There are 3 best solutions below

4
leftaroundabout On BEST ANSWER

You can always write unconstrained polymorphic function, that doesn't require any typeclass. A simple example is

length :: [a] -> Int

– this works without a typeclass, and (well, because) it works for any type a whatsoever. Namely, length doesn't actually care what the values in that list are, it only cares about the structure in which those values are contained. It never actually does anything with those values themselves, and the polymorphic type actually guarantees that.

If the polymorphic task you need is of this form, i.e. a type that you don't actually need to access, you just know it's there, then you should not write/invoke a type class, just use ML-style parametric polymorphism as in length. However, quite often you will need to access the values themselves, inspect them in some way. Doing that without however limiting you to a particular concrete type is what type classes are there for. Eq, as you quoted yourself, is an example.

0
developer_hatch On

There is a difference between polymorphic fuctions in OOP and in haskell, I say it because the term "polymorphism " is usually used in OOP.

Functions over list, by example, are polymorphic:

cons:: a -> [a] -> [a]
cons x xs = x:xs

where a is the polymorphic type, and there is no typeclass there.

By the way, there is a way to implement quickly typeclasses, by default, such as Eq or Show, by example:

data MBool = MTrue | MFalse deriving (Eq, Show)

So, the difference is that the typeclass is a constraint, imagine this function with lists:

mapShow :: Show a =>  [a] -> [String]
mapShow = map show

That's different, because now, a is restricted, it can't be any "a". It should implement the typeclass Show.

In conclusion, you can see that a type in cons function is more generic or abstract than Show => a -> a type in mapShow function.

0
willeM_ Van Onsem On

Is type class a way to define polymorphic functions?

Yes, it is a way. But not the only way. For example parametric polymorphism simply means that if you define a function like init :: [a] -> [a], it will work for any a. Type classes are used for ad-hoc polymorphism: depending on the type, the implementation can be entirely different. This in contrast to parametric polymorphism, where the head function is always the same, regardless the type for a.

Is type class the only way to define polymorphic functions?

No, see the previous section.

Can I define == and /= for Bool (and any other type) without using type class Eq?

That depends on whether the implementation is the same for all types or not. You can use the -XNoImplicitPrelude flag to avoid importing the Prelude, and then you can define your own (==) function.