2016-12-13 9 views
5

Haskellを学んでください、あなたのBMIを計算する例があります。自分でこの例を実行しようとした場合HaskellのRealFloatタイプは何のために使われますか?

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 

私はちょうどNumOrd型クラスを使用してエラーを解決することができませんでした。なぜこのコードを動作させるにはRealFloat typeclassを使用する必要がありますか? NumでカバーされていないRealFloatの特典は何ですか?

+2

GHCがどのようなものであるかを見極めるために型署名を残すようにしてください。必要なすべての制約を正しく識別できる必要があります。この関数定義で使用されている演算子の多くは型抜きからのものなので、これらの型クラスを実装する必要がある型を持つ必要があります。 – bheklilr

+0

@bheklilrああ、うわー、わかるよ。ご意見ありがとうございます。私はそれを試してみました。 GHCは 'bmiTell ::(分数a、Ord a)=> a - > a - > [Char]'をタイプシグネチャとして返しました。これはコードに入力すると明らかに機能します。それは少し意味があります。私はまだ 'bmiTell ::(Num a、Ord a)=> a - > a - > [Char]'がうまくいかない理由について混乱しています。 'Num'型のクラスには複素数も含まれているのでしょうか?複雑な数字は注文できないと思いますか? – user2407334

+1

@ user2407334 'Num'は* too *一般的なもので、'/'が定義されていない' Int'のような型を含みます。 – chepner

答えて

6

Numは十分ではありませんが、この例ではRealFloatが実際には過剰です。 (/)のために必要であるFractionalは、十分に良いです:

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

適切な署名、その後、次のようになります。Fractionalがサポートするすべてをカバーしながら、

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

RealFloatは、浮動小数点型のためのクラスです。実質部門。 DoubleRealFloat(またであり、それはRealFloatのスーパークラスであるため)。 Data.Ratioから得られるRatioの有理数のタイプは、RealFloatではないFractionalの例です。

も参照してください。ここに示したように、おそらく本のほうがRealFloatを使用していた可能性があると考えるベンの回答。

3

duplodeの答えに記載されている/に加えて、18.5のような非整数リテラルを使用します。それらはすべてNumタイプ(どのようなものが18.5 :: Integerなのでしょう?)として使用することはできません。したがって、あなたのファンクションが呼び出し側が好きなタイプのNumを処理できると約束することはできません。

私は単一の制約を記述することのみが必要であるように、本は、それはまた、(RealFracReal経由)Ordを暗示という理由だけでRealFloatを使用しています疑い。複数の制約により、この例題はより複雑で威圧的に見えるかもしれませんが、これは演習のポイントではありません。

+0

本の作者による可能性のある理論的根拠を歓迎します。私はそれが支払うかどうか分かりません(より費用がかかります:より明白なクラスの代わりに軽度の難解なクラスを導入する、または焦点を当てていない機能についての副作用を作成していますか?)が、どちらの方法でも議論することができます。 – duplode

関連する問題