简体   繁体   中英

Haskell Location Definition “No instance for (Fractional Int) arising from a use of ‘/’”

I'm getting the error " No instance for (Fractional Int) arising from a use of '/' ", from inside a local definition in a function I'm trying to make which determines how many of the (three) given integers are above the average of all of the given integers. So I've created a local definition inside the function to calculate the average so I can then use it for guard checks. I've used the same code in a separate definition (in another file) to calculate the average and it works. I've tried putting the " fromIntegral " function call in different places but it's not working, where am I going wrong?

Here's the code:

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
    | a > average && b > average = 2
    | a > average && c > average = 2
    | b > average && c > average = 2
    | a > average = 1
    | b > average = 1
    | c > average = 1
    | otherwise = 0
                where
                average = fromIntegral (a + b + c) / 3

The error is being flagged up on the last line.

Thanks.

You're comparing a (which is an Int ) and average (which is Fractional a => a ). Since (>) :: a -> a Bool , GHC presumes that average is also an Int , which doesn't work. You either need to change average to Int (for example via round ) or a , b and c to Double or Float .

You can also compare integers instead. The idea is that x < (a + b + c)/3 is equivalent to 3*x < a + b + c .

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
    | gti a av && gti b av = 2
    | gti a av && gti c av = 2
    | gti b av && gti c av = 2
    | gti a av = 1
    | gti b av = 1
    | gti c av = 1
    | otherwise = 0
        where 
            av = a + b + c
            gti x m = 3*x > m

Here's a cleaner version of the solution you came up with:

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
    | a' > average && b' > average = 2
    | a' > average && c' > average = 2
    | b' > average && c' > average = 2
    | a' > average = 1
    | b' > average = 1
    | c' > average = 1
    | otherwise = 0
  where
    average = a' + b' + c' / 3
    a' = fromIntegral a
    b' = fromIntegral b
    c' = fromIntegral c

You can simplify this even further to:

howManyAboveAverage a b c = length (filter (> average) [a', b', c'])
  where
    average = a' + b' + c' / 3
    a' = fromIntegral a
    b' = fromIntegral b
    c' = fromIntegral c

I've managed to resolve this by adding "fromIntegral" in front of any parameter that was compared to the average.

New (working) code:

howManyAboveAverage :: Int -> Int -> Int -> Int
howManyAboveAverage a b c
    | fromIntegral a > average && fromIntegral b > average = 2
    | fromIntegral a > average && fromIntegral c > average = 2
    | fromIntegral b > average && fromIntegral c > average = 2
    | fromIntegral a > average = 1
    | fromIntegral b > average = 1
    | fromIntegral c > average = 1
    | otherwise = 0
                where
                average = fromIntegral (a + b + c) / 3

It looks a bit messy / cumbersome so if anyone has any other (cleaner) suggestions please let me know.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM