[Haskell-cafe] Polymorphism/monomorphism (and the restriction)

Aaron McDaid haskell-cafe at aaronmcdaid.com
Thu Sep 21 18:27:38 EDT 2006


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 at 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.


More information about the Haskell-Cafe mailing list