在了解您的Haskell 书籍中,有一个有关计算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)
当我尝试自己执行此示例时,我使用
(Num a) => a -> a -> String
作为方法的类型签名。但是,这引发了以下错误: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
我仅使用
Num
和Ord
类型类无法解决该错误。为什么需要使用RealFloat
typeclass来使这段代码起作用? RealFloat
未涵盖的Num
有何特别之处? 最佳答案
尽管Num
不够,但在此示例中RealFloat
确实过多。 Fractional
必需的(/)
足够好:
GHCi> :t (/)
(/) :: Fractional a => a -> a -> a
那么,适当的签名将是:
bmiTell :: (Fractional a, Ord a) => a -> a -> String
RealFloat
是浮点类型的类,而 Fractional
涵盖支持实数除法的所有内容。 Double
是RealFloat
(也是Fractional
,因为它是RealFloat
的 super class )。可以从 Ratio
获得的有理数的Data.Ratio
类型是不是Fractional
的RealFloat
的示例。另请参阅:Ben's answer,它考虑了为什么本书可能使用
RealFloat
而不是此处显示的可能更简单的替代方法。