Search code examples
haskellfunctional-programmingmonomorphism-restriction

Confusing types in ghci


Here is my code:

n = [(a,b) | a <- [1..5],b <- [1..5]]
calcBmis xs = [bmi | (w, h) <- xs,let bmi = w / h ^ 2]  

When trying to apply calcBmis to n, I get the following error:

*Charana> calcBmis n

<interactive>:220:1:
    No instance for (Fractional Integer)
    arising from a use of ‘calcBmis’
    In the expression: calcBmis n
    In an equation for ‘it’: it = calcBmis n

Further investigation in ghci:

*Charana> :t calcBmis
calcBmis :: Fractional t => [(t, t)] -> [t]
*Charana> :t n
n :: [(Integer, Integer)]

What I'm assuming is that the list I produce is of type (Integer,Integer), but that cannot be processed in the calcBmis, which only takes in Fractional. Any idea how to fix this problem?


Solution

  • you can use div instead of (/):

    calcBmis xs = [ bmi | (w,h) <- xs, let bmi = (w `div` h)^2 ]
    
    Prelude> :t calcBmis
    calcBmis :: Integral t => [(t, t)] -> [t]
    
    Prelude> calcBmis n
    [1,0,0,0,0,4,1,0,0,0,9,1,1,0,0,16,4,1,1,0,25,4,1,1,1]
    

    as you can see this version can deal with all Integral values - but of course will truncate (because of div).

    or you can map everything with fromIntegral:

    calcBmis xs = [ bmi | (w,h) <- xs, let bmi = (fromIntegral w / fromIntegral h)^2 ]
    
    Prelude> :t calcBmis
    calcBmis:: (Fractional t, Integral t1, Integral t2) => [(t1, t2)] -> [t]
    

    Which then will produce fractional values:

    Prelude> calcBmis n
    [1.0,0.25,0.1111111111111111
    ,6.25e-2
    ,4.000000000000001e-2
    ,4.0
    ,1.0
    ,0.4444444444444444
    , ... ]
    

    in either case it will work with all inputs as long as they are an instance of Integral - the second version will even accept pairs of different integrals ;)