简体   繁体   中英

Haskell Confusing Type Classes / Polymorphism

So basically I've past learning this part way back a month ago, and I can do more complicated stuff but I still don't understand when I need "Ord" or "Eq" etc in my type definitions. When I look it up online its just so confusing to me for some reason.

Eg

my_min :: Ord a => a -> a -> a
my_min n1 n2 = if n1<n2 then n1 else n2

Why does this need Ord? Can you give an example of when you need Eq as well (a very simple one)? I need a very clear, basic explanation of when you need to put these, what to look out for to do that, and how to avoid using these at all if possible.

Usually I just need something like "[Int] -> Int -> [Int]" so i know ok this function takes an integer list and an integer, and returns an integer list. But when it includes Eq or Ord I have no idea.

What about this Eq type in this example I found in my lecture notes about finding two lists is identical, how does it apply?

identical :: Eq a =>[a]->[a]->Bool 
identical [] [] = True 
identical [] _ = False 
identical _ [] = False 
identical (h1:t1) (h2:t2) =
    if h1==h2 
        then (identical t1 t2) 
        else False 

Thank you.

Ord implies that the thing can be ordered, which means that you can say a is smaller (or greater) than b . Using only Eq is like saying: I know that these two items are not the same, but I cannot say which one is greater or smaller. For example if you take a traffic light as a data type:

data TLight = Red | Yellow | Green deriving (Show, Eq)

instance Eq TLight where
  Green == Green = True
  Yellow == Yellow = True
  Red == Red = True
  _ == _ = False

Now we can say: Red is unequal to Yellow but we cannot say what is greater. This is the reason why you could not use TLight in your my_min . You cannot say which one is greater.

To your second question: "Is there any case where you have to use Eq and Ord ?":

Ord implies Eq . This means that if a type can be ordered, you can also check it for equality.

You said you have mostly dealt with [Int] -> Int -> [Int] and you then knew it takes a list of integer and an integer and returns an integer. Now if you want to generalise your function you have to ask yourself: Do the possible types I want to use in my function need any special functionality? like if they have to be able to be ordered or equated.

Lets do a few examples: Say we want to write a function which takes a list of type a and an element of type a and returns the lisy with the element consed onto it. How would it's type signature look like? Lets start with simply this:

consfunc :: [a] -> a -> [a]

Do we need any more functionality? No! Our type a can be anything because we do not need it to be able to be ordered simple because that is mot what our function should do.

Now what if we want to take a list and an element and check if the element is in the list already? The beginning type signature is:

elemfunc :: [a] -> a -> Bool

Now does our element have to be able to do something special? Yes it does, we have to be able to check if it is equal to any element in the list, which says that our type a has to be equatable, so our type signature looks like this:

elemfunc :: (Eq a) => [a] -> a -> Bool

Now what if we want to take a list and a element and insert it if it is smaller than the first element? Can you guess how the type signature would look like?

Lets begin with the standard again and ask ourselves: Do we need more than just knowing that the element and the list have to be of the same type: Yes, becuase our condition needs to perform a test that requires our type to be ordered, we have to include Ord in our type signature:

conditionalconsfunc :: (Ord a) => [a] -> a -> [a]

Edit:

Well you want to see if two lists are identical, so there are two things you have to look out for:

Your lists have to contain the same type and the things inside the list have to be equatable, hence the Eq .

If you are working with fixed types like Int , you never need class constraints. These only arise when working with polymorphic code.

You need Eq if you ever use the == or /= functions, or if you call any other functions that do. (Ie, if you call a function that has Eq in its type, then your type needs to have Eq as well.)

You need Ord if you ever use < , > , compare or similar functions. (Again, or if you call something that does.)

Note that you do not need Eq if you only do pattern matching. Thus, the following are different:

factorial 1 = 1
factorial n = n * factorial (n-1)
-- Only needs Num.

factorial n = if n == 1 then 1 else  n * factorial (n-1)
-- Needs Num and Eq.

factorial n = if n < 2 then 1 else n * factorial (n-1)
-- Needs Num, Eq and Ord. (But Ord implies Eq automatically.)

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