Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is RealFloat type in Haskell used for?

In the Learn You A Haskell book, there is an example about calculating your BMI.

bmiTell :: (RealFloat a) => a -> a -> String
bmiTell weight height
    | bmi <= skinny = "You're underweight, you emo, you!"
    | bmi <= normal = "You're supposedly normal. Pffft, I bet you're ugly!"
    | bmi <= fat    = "You're fat! Lose some weight, fatty!"
    | otherwise     = "You're a whale, congratulations!"
    where bmi = weight / height ^ 2
          (skinny, normal, fat) = (18.5, 25.0, 30.0)

When I tried to do this example by myself, I used (Num a) => a -> a -> String as the type signature for the method. However that threw the following error:

Could not deduce (Ord a) arising from a use of ‘<=’
    from the context (Num a)
      bound by the type signature for
                 bmiTell :: Num a => a -> a -> String
      at scratch.hs:96:12-38
    Possible fix:
      add (Ord a) to the context of
        the type signature for bmiTell :: Num a => a -> a -> String

I was not able to resolve the error just using the Num and Ord typeclasses. Why do I need to use RealFloat typeclass to make this piece of code work? What is so special about RealFloat that is not covered by Num?

like image 560
user2407334 Avatar asked Dec 13 '16 17:12

user2407334


2 Answers

While Num is not enough, RealFloat is indeed excessive for this example. Fractional, which is necessary for (/), is good enough:

GHCi> :t (/)
(/) :: Fractional a => a -> a -> a

An appropriate signature, then, would be:

bmiTell :: (Fractional a, Ord a) => a -> a -> String

RealFloat is a class for floating point types, while Fractional covers everything that supports real division. Double is a RealFloat (and also a Fractional, as that is a superclass of RealFloat). The Ratio type for rational numbers, available from Data.Ratio, is an example of a Fractional that isn't a RealFloat.

See also: Ben's answer, which considers why the book might have used RealFloat rather than the arguably simpler alternative shown here.

like image 164
duplode Avatar answered Sep 25 '22 23:09

duplode


In addition to / as noted in duplode's answer, you use non-integer literals like 18.5. Those can't be used as every Num type (what would 18.5 :: Integer be, for example?), so you can't promise that your function can handle any Num type the caller likes.

I suspect the book uses RealFloat simply because it also implies Ord (via RealFrac and Real), so that it was only necessary to write a single constraint. Multiple constraints might have made the example look more complex and intimidating, with a feature that isn't the point of the exercise.

like image 32
Ben Avatar answered Sep 22 '22 23:09

Ben