什么是Haskell中的RealFloat类型用于?

use*_*334 8 haskell typeclass

Learn You A 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)
Run Code Online (Sandbox Code Playgroud)

当我试图自己做这个例子时,我用作(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
Run Code Online (Sandbox Code Playgroud)

我只能使用NumOrd类型类来解决错误.为什么我需要使用RealFloat类型类来使这段代码工作?有什么特别之处RealFloat不在于Num

dup*_*ode 10

虽然Num还不够,但RealFloat这个例子确实过分了.Fractional,这是必要的(/),足够好:

GHCi> :t (/)
(/) :: Fractional a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

那么,适当的签名将是:

bmiTell :: (Fractional a, Ord a) => a -> a -> String
Run Code Online (Sandbox Code Playgroud)

RealFloat是一个浮点类型的类,同时Fractional涵盖了支持实际划分的所有内容.Double是一个RealFloat(也是一个Fractional,因为它是一个超类RealFloat).Ratio有理数的类型,可从中获得Data.Ratio,是一个Fractional不是a 的例子RealFloat.

另请参阅:Ben的答案,该答案考虑了本书可能使用的原因,RealFloat而不是此处所示的可论证的更简单的替代方案.


Ben*_*Ben 5

除了/在duplode的答案中提到的,你还使用非整数文字18.5.那些不能用作每种Num类型(18.5 :: Integer例如,什么?),所以你不能保证你的函数可以处理Num调用者喜欢的任何类型.

我怀疑这本书的使用RealFloat仅仅是因为它也暗示了Ord(通过RealFracReal),所以只需编写一个约束.多个约束可能使示例看起来更复杂和令人生畏,其功能不是练习的重点.

  • 很好地呼吁了本书作者的可能理由。我不确定它是否有回报(更昂贵的是:引入一个稍微深奥的类而不是一个更明显的类,或者对一个没有被关注的功能发表意见?),但无论哪种方式都可以争论. (3认同)