Polymorphism/monomorphism (and the restriction)

Hi, I think the following might help a little in understanding the monomorphic restriction (which I don't fully understand myself). I'm a bit of a newbie so apologies in advance if I've made a mistake or if my description isn't as useful to others as it seems to me. I've been following a thread on haskell@haskell.org and I think the below might help. I used GHCi, version 6.2.2 (it fails in hugs but that seems to be because of hugs non-compliance with the standard in this case). First off, I'm guessing that I'm getting Haskell98 behaviour here and not some GHCi extension. Please tell me if this is not the case. Run the code listing at the bottom of this email and you should get the output which I've also listed below. This code experiments with "Int", "Float" and "(Num a) => a", and I tried to print x*2 and x/2 for each. (4::Int)/2 isn't allowed because / isn't defined for Ints. You can see that kN :: (Num a) => a took two different types depending on what method ( / or * ) was applied to it. kN / 2 = 2.0 kN * 2 = 8 kN/2 is a Float (it can't use Int as / isn't defined for Int, so it uses Float, for which / is defined). kN*2 is an Int. The above outputs demonstrates polymorphism, doesn't it? i.e. Not only has the compiler got a variety of types to choose from, but a variety of types can be used at runtime? The output for kI and kF is obvious. The interesting thing is that k behaves as a Float in both cases. This is monomorphism isn't it? i.e. the compiler may have a variety of types to choose from, but it picks one and sticks to it for every usage. In summary, k didn't give the same outputs as kN. And the monomorphism restriction is a rule which means that sometimes things are forced to a monomorphic type (like k as Float here) when it could have given it a polymorphic type like "kN :: (Num a) => a" I'm fairly new to these lists, so apologies if I'm covering old ground again. My first aim is to understand exactly what polymorphism and monomorphism is and demonstrate corresponding results, before thinking about the restriction. Thanks, Aaron -- The code kI :: Int kI = 4 kF :: Float kF = 4 kN :: (Num a) => a kN = 4 k = 4 main = do p "kI * 2" $ kI * 2 p "kF / 2" $ kF / 2 p "kF * 2" $ kF * 2 p "kN / 2" $ kN / 2 p "kN * 2" $ kN * 2 p "k / 2" $ k / 2 p "k * 2" $ k * 2 p :: (Show a) => String -> a -> IO () p s = putStrLn.(s++).(" = "++).show -- the output - remember kI / 2 is not possible. kI * 2 = 8 kF / 2 = 2.0 kF * 2 = 8.0 kN / 2 = 2.0 kN * 2 = 8 k / 2 = 2.0 k * 2 = 8.0 -- PS: If you delete the k / 2 line from the program, then k * 2 becomes simply 8 (not 8.0). It uses Int if possible, and Float if that's not available.

Aaron McDaid wrote:
This code experiments with "Int", "Float" and "(Num a) => a", and I tried to print x*2 and x/2 for each. (4::Int)/2 isn't allowed because / isn't defined for Ints.
More exactly: (/) is a member function of the Fractional class, and Int is not an instance of this class.
You can see that kN :: (Num a) => a took two different types depending on what method ( / or * ) was applied to it. kN / 2 = 2.0 kN * 2 = 8 kN/2 is a Float (it can't use Int as / isn't defined for Int, so it uses Float, for which / is defined).
kN/2 has type Fractional a => a (try ":t kN/2" in ghci) and when you apply it to show, a specific type will be chosen by defaulting (Haskell report section 4.3.4). Without an explicit default declaration, Haskell will try first Integer, then Double. Integer is not an instance of Fractional, so Double will be used. You will get the types you claim to get when you add the line "default (Int,Float)" at the top of your file.
kN*2 is an Int.
By itself, it's Num a => a, then it will default to Integer.
The above outputs demonstrates polymorphism, doesn't it? i.e. Not only
Polymorphism (or rather: overloading) and defaulting.
has the compiler got a variety of types to choose from, but a variety of types can be used at runtime?
It only chooses (i.e. tries in order) the types given in the (posibly implicit) default declaration. At runtime it doesn't care about types, but of course the same polymorphic or overloaded function can be used with different types.
The interesting thing is that k behaves as a Float in both cases. This is monomorphism isn't it? i.e. the compiler may have a variety of types to choose from, but it picks one and sticks to it for every usage. In summary, k didn't give the same outputs as kN.
Since (/) is used with k, it must be Fractional, so as in kN/2, defaulting makes it Double.
I'm fairly new to these lists, so apologies if I'm covering old ground again. My first aim is to understand exactly what polymorphism and monomorphism is and demonstrate corresponding results, before thinking about the restriction.
The type of map :: (a -> b) -> [a] -> [b] is polymorphic. Here we are talking about overloading, also known as ad-hoc polymorphism. In Haskell overloaded functions are recognizable by the context in their type, e.g.: abs :: Num a => a -> a I think I also mixed this up in one of my earlier mails. Seems we need a glossary. Bye Christian Sievers
participants (2)
-
Aaron McDaid
-
Christian Sievers