Learn You a Haskell for Great Good! - Miran Lipovaca [14]
ghci> :t (>)
(>) :: (Ord a) => a -> a -> Bool
The type of > is similar to the type of ==. It takes two items as parameters and returns a Bool, which tells us if some relation between those two things holds or not.
All the types we’ve covered so far (again, except for functions) are instances of Ord. Ord covers all the standard comparison functions such as >, <, >=, and <=.
The compare function takes two values whose type is an Ord instance and returns an Ordering. Ordering is a type that can be GT, LT, or EQ, which represent greater than, lesser than, or equal, respectively.
ghci> "Abrakadabra" < "Zebra"
True
ghci> "Abrakadabra" `compare` "Zebra"
LT
ghci> 5 >= 2
True
ghci> 5 `compare` 3
GT
ghci> 'b' > 'a'
True
The Show Type Class
Values whose types are instances of the Show type class can be represented as strings. All the types we’ve covered so far (except for functions) are instances of Show. The most commonly used function that operates on instances of this type class is show, which prints the given value as a string:
ghci> show 3
"3"
ghci> show 5.334
"5.334"
ghci> show True
"True"
The Read Type Class
Read can be considered the opposite type class of Show. Again, all the types we’ve covered so far are instances of this type class. The read function takes a string and returns a value whose type is an instance of Read:
ghci> read "True" || False
True
ghci> read "8.2" + 3.8
12.0
ghci> read "5" - 2
3
ghci> read "[1,2,3,4]" ++ [3]
[1,2,3,4,3]
So far so good. But what happens if we try entering read "4"?
ghci> read "4"
Ambiguous type variable 'a' in the constraint: 'Read a' arising from a use of 'read' at Probable fix: add a type signature that fixes these type variable(s) GHCi is telling us that it doesn’t know what we want in return. Notice that in the previous uses of read, we did something with the result afterward, which let GHCi infer the kind of result we wanted. If we used it as a Boolean, for example, it knew it had to return a Bool. But now it knows we want some type that is part of the Read class, but it doesn’t know which one. Let’s take a look at the type signature of read: ghci> :t read read :: (Read a) => String -> a Note String is just another name for [Char]. String and [Char] can be used interchangeably, but we’ll mostly be sticking to String from now on because it’s easier to write and more readable. We can see that the read function returns a value whose type is an instance of Read, but if we use that result in some way, it has no way of knowing which type. To solve this problem, we can use type annotations. Type annotations are a way to explicitly tell Haskell what the type of an expression should be. We do this by adding :: to the end of the expression and then specifying a type: ghci> read "5" :: Int 5 ghci> read "5" :: Float 5.0 ghci> (read "5" :: Float) * 4 20.0 ghci> read "[1,2,3,4]" :: [Int] [1,2,3,4] ghci> read "(3, 'a')" :: (Int, Char) (3, 'a') The compiler can infer the type of most expressions by itself. However, sometimes the compiler doesn’t know whether to return a value of type Int or Float for an expression like read "5". To see what the type is, Haskell would need to actually evaluate read "5". But since Haskell is a statically typed language, it needs to know all the types before the code is compiled (or in the case of GHCi, evaluated). So we need to tell Haskell, “Hey, this expression should have this type, in case you didn’t know!” We can give Haskell only the minimum amount of information it needs to figure out which type of value read should return. For instance, if we’re using read and then cramming its result into a list, Haskell can use the list to figure out which type we want by looking at the other elements of the list: ghci> [read "True", False, True, False] [True, False, True, False] Since we used read "True" as an element in a list of Bool values, Haskell sees that the type of