A round function or how to deal with type-defaults warnings

I am trying to write a round function (I know there exist modules for this, but as an exercise I try it myself) with the following given signature:

rndN :: Int -> Double -> Double

Here the implementation I came up with:

rndN n x = fromIntegral (round (x * dshift)) / dshift
    where
        dshift = 10^n :: Double

When it runs it does what I want, but during compile I get a warning from GHC (I use -Wall to be able to hunt down all warnings):

Warning: [-Wtype-defaults]
    • Defaulting the following constraint to type ‘Integer’
        Integral a0 arising from a use of ‘fromIntegral’
    • In the first argument of ‘(/)’, namely
        ‘fromIntegral (round (x * dshift))’
      In the expression: fromIntegral (round (x * dshift)) / dshift

I don’t understand how to give in the function the compiler all the necessary clues, so that it doesn’t need to use the defaults. I guess fromIntegral converts to any Num and at that point in the formula I haven’t told GHC that I want Double specifically…

I am a bit lost…

1 Like

I think the type-defaults warning is just trying to let you know that GHC picked Integer rather than something else like Int16 or Int64 for the result of round. Integer is a pretty safe pragmatic choice, if the compiler picked Int16, your function would run into problems when (x * dshift) was out of the range of Int16.

If you wanted you could give a type signature to (round (x * dshift)), but often times those type signatures add noise that is not needed because the compiler made the correct choice to begin with.

1 Like

Of course! That’s it: It is not about the overall Double result but about the Integer subresult. Thank you!

I want to. With your suggestion I got it warnings-free:

rndN n x = fromIntegral (round (x * dshift)::Integer) / dshift

I’m a happy camper now! :slight_smile:

I agree. In production coding it might make more sense to quiet the warning around this function (Is this possivle with ghc?), but I am in exercise/learning mode.

Thanks again.

1 Like

Quite. The clue in the message is ... arising from a use of ‘fromIntegral’

Prelude> :type fromIntegral
fromIntegral :: (Integral a, Num b) => a -> b

So your program isn’t specifying the specific type of the result from fromIntegral, all the function’s signature tells is that is must be Integral a for some a. And the defaulting rules for that say Integer.

rndN n x = fromIntegral (round (x * dshift) :: Integer) / dshift
    where ...                            -- ^^^^^^^^^^

That is, put an inline signature with ::. As @waivio says, that does add noise/make it more difficult for the human reader. Often (but not in this case) you need an extra pair of parens to limit where the :: applies.

1 Like