Haskell - Types and Type Class

Haskell is a functional language and it is strictly typed, which means the data type used in the entire application will be known to the compiler at compile time.
In Haskell, every statement is considered as a mathematical expression and the category of this expression is called as a Type. You can say that "Type" is the data type of the expression used at compile time.
To learn more about the Type, we will use the ":t" command. In a generic way, Type can be considered as a value, whereas Type Class can be the considered as a set of similar kind of Types. In this chapter, we will learn about different Inbuilt Types.
Int is a type class representing the Integer types data. Every whole number within the range of 2147483647 to -2147483647 comes under the Int type class. In the following example, the function fType() will behave according to its type defined.
fType :: Int -> Int -> Int 
fType x y = x*x + y*y
main = print (fType 2 4) 
Here, we have set the type of the function fType() as int. The function takes two int values and returns one int value. If you compile and execute this piece of code, then it will produce the following output −
sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts 
sh-4.3$ main
20

Integer can be considered as a superset of Int. This value is not bounded by any number, hence an Integer can be of any length without any limitation. To see the basic difference between Int and Integer types, let us modify the above code as follows −
fType :: Int -> Int -> Int 
fType x y = x*x + y*y 
main = print (fType 212124454 44545454454554545445454544545)
If you compile the above piece of code, the following error message will be thrown −
main.hs:3:31: Warning:            
   Literal 44545454454554545445454544545 is out of the Int range -
   9223372036854775808..9223372036854775807 
Linking main ...

This error occurred because our function fType() expecting one Int type value, and we are passing some real big Int type value. To avoid this error, Let us modify the type "Int" with "Integer" and observe the difference.
fType :: Integer -> Integer -> Integer 
fType x y = x*x + y*y 
main = print (fType 212124454 4454545445455454545445445454544545) 
Now, it will produce the following output −
sh-4.3$ main
1984297512562793395882644631364297686099210302577374055141

Take a look at the following piece of code. It shows how Float type works in Haskell −
fType :: Float -> Float -> Float 
fType x y = x*x + y*y 
main = print (fType 2.5 3.8)
The function takes two float values as the input and yields another float value as the output. When you compile and execute this code, it will produce the following output −
sh-4.3$ main
20.689999 

Double is a floating point number with double precision at the end. Take a look at the following example −
fType :: Double -> Double -> Double 
fType x y = x*x + y*y 
main = print (fType 2.56 3.81)
When you execute the above piece of code, it will generate the following output −
sh-4.3$ main 
21.0697

Bool is a Boolean Type. It can be either True or False. Execute the following code to understand how the Bool type works in Haskell −
main = do  
   let x = True 
   
   if x == False 
      then putStrLn "X matches with Bool Type" 
   else putStrLn "X is not a Bool Type" 
Here, we are defining a variable "x" as a Bool and comparing it with another Boolean value to check its originality. It will produce the following output −
sh-4.3$ main
X is not a Bool Type 

Char represent Characters. Anything within a single quote is considered as a Character. In the following code, we have modified our previous fType() function to accept Char value and return Char value as output.
fType :: Char-> Char 
fType x = 'K' 
main = do  
   let x = 'v' 
   print (fType x) 
The above piece of code will call fType() function with a char value of 'v' but it returns another char value, that is, 'K'. Here is its output −
sh-4.3$ main 
'K'

Note that we are not going to use these types explicitly because Haskell is intelligent enough to catch the type before it is declared. In the subsequent chapters of this tutorial, we will see how different types and Type classes make Haskell a strongly typed language.
EQ type class is an interface which provides the functionality to test the equality of an expression. Any Type class that wants to check the equality of an expression should be a part of this EQ Type Class.
All standard Type classes mentioned above is a part of this EQ class. Whenever we are checking any equality using any of the types mentioned above, we are actually making a call to EQ type class.
In the following example, we are using the EQ Type internally using the "==" or "/=" operation.
main = do 
   if 8 /= 8 
      then putStrLn "The values are Equal" 
   else putStrLn "The values are not Equal"
It will yield the following output −
sh-4.3$ main 
The values are not Equal 

Ord is another interface class which gives us the functionality of ordering. All the types that we have used so far are a part of this Ord interface. Like EQ interface, Ord interface can be called using ">", "<", "<=", ">=", "compare".
Please find below example where we used “compare ” functionality of this Type Class.
main = print (4 <= 2) 
Here, the Haskell compiler will check if 4 is less than or equal to 2. Since it is not, the code will produce the following output −
sh-4.3$ main 
False

Show has a functionality to print its argument as a String. Whatever may be its argument, it always prints the result as a String. In the following example, we will print the entire list using this interface. "show" can be used to call this interface.
main = print (show [1..10]) 
It will produce the following output on the console. Here, the double quotes indicate that it is a String type value.
sh-4.3$ main 
"[1,2,3,4,5,6,7,8,9,10]" 

Read interface does the same thing as Show, but it won’t print the result in String format. In the following code, we have used the read interface to read a string value and convert the same into an Int value.
main = print (readInt "12") 
readInt :: String -> Int 
readInt = read 
Here, we are passing a String variable ("12") to the readInt method which in turn returns 12 (an Int value) after conversion. Here is its output −
sh-4.3$ main 
12

Enum is another type of Type class which enables the sequential or ordered functionality in Haskell. This Type class can be accessed by commands such as Succ, Pred, Bool, Char, etc.
The following code shows how to find the successor value of 12.
main = print (succ 12) 
It will produce the following output −
sh-4.3$ main
13

All the types having upper and lower bounds come under this Type Class. For example, Int type data has maximum bound of "9223372036854775807" and minimum bound of "-9223372036854775808".
The following code shows how Haskell determines the maximum and minimum bound of Int type.
main = do 
   print (maxBound :: Int) 
   print (minBound :: Int) 
It will produce the following output −
sh-4.3$ main
9223372036854775807
-9223372036854775808

Now, try to find the maximum and minimum bound of Char, Float, and Bool types.
This type class is used for numeric operations. Types such as Int, Integer, Float, and Double come under this Type class. Take a look at the following code −
main = do 
   print(2 :: Int)  
   print(2 :: Float) 
It will produce the following output −
sh-4.3$ main
2
2.0

Integral can be considered as  a  sub-class of the Num Type Class. Num Type class holds all types of numbers, whereas Integral type class is used only for integral numbers. Int and Integer are the types under this Type class.
Like Integral, Floating is also a part of the Num Type class, but it only holds floating point numbers. Hence, Float and Double come under this type class.
Like any other programming language, Haskell allows developers to define user-defined types. In the following example, we will create a user-defined type and use it.
data Area = Circle Float Float Float  
surface :: Area -> Float   
surface (Circle _ _ r) = pi * r ^ 2   
main = print (surface $ Circle 10 20 10 ) 
Here, we have created a new type called Area. Next, we are using this type to calculate the area of a circle. In the above example, "surface" is a function that takes Area as an input and produces Float as the output.
Keep in mind that "data" is a keyword here and all user-defined types in Haskell always start with a capital letter.
It will produce the following output −
sh-4.3$ main
314.15927

 Print
 Add Notes
 Bookmark this page