module TypeClasses where import Question typeClasses = do h2 $ text "Something about type classes" p <#>Why did we write div, and not /, in the example with the error message in the beginning of this document? prompts' [ ("div 4 0", "Program error: divide by zero") , ("4/0", "Inf") ] <#>We can see that div and / don't give the same result. Let's learn some more about these functions. How? ?> do p <#>We use the command :i (:info): prompts' [ (":i div" , "infixl 7 `div`\n\ \div :: Integral a => a -> a -> a -- class member" ) , (":i /" , "infixl 7 /\n\ \(/) :: Fractional a => a -> a -> a -- class member" ) ] p <#>You don't need to worry about the lines including infixl at the moment.The interesting part is that div and / have different types. <#>The function div takes as input two objects of "Integral" type, i.e. an integer type, and returns as output an object of integer type. How does integer division work? ?> do p <#>Did you try it? prompts' [ ("div 4 2", "2") , ("div 4 3", "1") , ("div 34 10", "3") ] p <#>Obviously we can't jump to any conclusions based on a few examples, but it seems plausible that div performs integer division. And that is also the case. -- Possibility to use QuickCheck. <#>Furthermore / works with objects of "Fractional" type, i.e. different kinds of fractions. How does division with fractions work? ?> do p <#>We can start by trying the same example as before: prompts' [ ("4/2", "2.0") , ("4/3", "1.33333333333333") , ("34/10", "3.4") ] <#>During the lecture you learnt that the result of a computation may vary depending on the type of the result. Above we didn't state a type, which forces Hugs to guess what the type should be. In this case there were several possible types. Usually (as you've already seen) one is presented with an error message, but in some cases Hugs will choose the type automatically. In this case Double was picked. Try with the type Ratio Integer (integer fraction) instead. The type of an expression is stated by typing <% tt $ text " :: " %>. ?> do prompts' [ ("4/2 :: Ratio Integer", "2 % 1") , ("4/3 :: Ratio Integer", "4 % 3") , ("34/10 :: Ratio Integer", "17 % 5") ] <#>Now we get normal division without the rounding that comes with floating point types (e.g. Double). This shows the importance of stating a type signature. Are there any more reasons? ?> do p <#>See the lecture notes. There is a slide with the heading "Always Specify Type Signatures!". -- Add a type signature to the temperature function. p <#>It's time to learn more about what Integral and Fractional stand for: prompts' [ ( ":i Integral" , "-- type class\n\ \...\n\ \class (Real a, Enum a) => Integral a where\n\ \ ...\n\ \ div :: a -> a -> a\n\ \ ...\n\ \\n\ \-- instances:\n\ \instance Integral Int\n\ \instance Integral Integer" ) , ( ":i Fractional" , "-- type class\n\ \...\n\ \class Num a => Fractional a where\n\ \ ...\n\ \ (/) :: a -> a -> a\n\ \ ...\n\ \\n\ \-- instances:\n\ \instance Fractional Float\n\ \instance Fractional Double\n\ \instance Integral a => Fractional (Ratio a)" ) ] p <#>Integral and Fractional are type classes. A certain type can belong to (be an instance of) different type classes. Above we can see that the built-in types Int and Integer, two kinds of integer types, both belong to Integral. Since Integral is a class for integer types, with operations such as integer division, this makes sense. p <#>Furthermore, we can see on the last line (even though it may be hard to understand at this stage), that if a is an integer type (Integral a), then the type of fractions with denominators and numerators of type a (Ratio a) is a fractional type (Fractional (Ratio a)). The built-in floating point types Float and Double are fractional types as well. Furthermore, we can see that in order for a type to be a fractional type, it must be a numerical type (Num a => Fractional a). <#>What is meant by a numerical type? ?> do prompts' [ ( ":i Num" , "-- type class\n\ \infixl 6 +\n\ \infixl 6 -\n\ \infixl 7 *\n\ \class (Eq a, Show a) => Num a where\n\ \ (+) :: a -> a -> a\n\ \ (-) :: a -> a -> a\n\ \ (*) :: a -> a -> a\n\ \ negate :: a -> a\n\ \ abs :: a -> a\n\ \ signum :: a -> a\n\ \ fromInteger :: Integer -> a\n\ \ fromInt :: Int -> a\n\ \\n\ \-- instances:\n\ \instance Num Int\n\ \instance Num Integer\n\ \instance Num Float\n\ \instance Num Double\n\ \instance Integral a => Num (Ratio a)" ) ] p <#>Numerical types support operations like addition (+) and multiplication (*), but not necessarily division. If you read the list of instances, you will see that all the types mentioned earlier today, apart from Boolean values (Bool), are numerical types. p <#>You will learn more about type classes later in this course, and you will also define types of your own.