2011-11-09 9 views
0
data V2 a = V2 a a deriving (Show, Eq) 

instance Num a => Num (V2 a) where 
    (-) (V2 x0 y0) (V2 x1 y1) = V2 (x0 - x1) (y0 - y1) 
    (+) (V2 x0 y0) (V2 x1 y1) = V2 (x0 + x1) (y0 + y1) 
    (*) (V2 x0 y0) (V2 x1 y1) = V2 (x0 * x1) (y0 * y1) 
    abs = undefined 
    signum = undefined 
    fromInteger = undefined 

instance Fractional a => Fractional (V2 a) where 
    (/) (V2 x0 y0) (V2 x1 y1) = V2 (x0/x1) (y0/y1) 
    recip = undefined 
    fromRational = undefined 

-- Multiply by scalar 
(*$) :: Num a => V2 a -> a -> V2 a 
(*$) (V2 x y) s = V2 (x * s) (y * s) 

-- Length of the vector 
len :: (Num a, Integral a, Floating b) => V2 a -> b 
len (V2 x y) = sqrt $ fromIntegral $ x * x + y * y 

normal :: (Num a, Integral a) => V2 a -> V2 a 
normal v = v *$ (1/len v) 

{- 

Math\V2.hs:31:20: 
    Could not deduce (Fractional a) arising from a use of `/' 
    from the context (Num a, Integral a) 
     bound by the type signature for 
       normal :: (Num a, Integral a) => V2 a -> V2 a 
     at Math\V2.hs:31:1-27 
    Possible fix: 
     add (Fractional a) to the context of 
     the type signature for 
      normal :: (Num a, Integral a) => V2 a -> V2 a 
    In the second argument of `(*$)', namely `(1/len v)' 
    In the expression: v *$ (1/len v) 
    In an equation for `normal': normal v = v *$ (1/len v) 

Math\V2.hs:31:22: 
    Could not deduce (Floating a) arising from a use of `len' 
    from the context (Num a, Integral a) 
     bound by the type signature for 
       normal :: (Num a, Integral a) => V2 a -> V2 a 
     at Math\V2.hs:31:1-27 
    Possible fix: 
     add (Floating a) to the context of 
     the type signature for 
      normal :: (Num a, Integral a) => V2 a -> V2 a 
    In the second argument of `(/)', namely `len v' 
    In the second argument of `(*$)', namely `(1/len v)' 
    In the expression: v *$ (1/len v) 

-} 

上記の通常の機能を実装する際に問題があります。どのように型チェックに合格することができますか?数値型クラスでエラーが発生しました

+0

妥当なデフォルト方法があるので、 'recip = undefined'を削除する必要があります。 – augustss

答えて

4

の3つのオプション:

  • あなたのタイプの署名を変更

    normal :: (Integral a, Floating b) => V2 a -> V2 b 
    

    そして(Floating b) => V2 b(Integral a) => V2 aを変換し、*$vにそれを適用する機能を指定します。

  • (等roundIntegral値に1/len vからFloating結果を変換します。

  • Landeiが示唆しているように、どこでもFloatingの使用を強制します。

len(Integral a) => V2 a取り込んで(Floating b) => bを返します。結果に1 /を実行しますが、それでもタイプは(Floating b) => bです。 *$のタイプからは、V2 aaが必要ですが、この場合はと(1/len v) :: (Floating b) => bがあります。これは同等のタイプではありません。

なので、何らかの形の強制が必要ですどこかです。

-1

見つけました。 lenは浮動小数点を返すため、浮動小数点数はnormalである必要があります。そうしないと あなたが

normal :: (Num a, Integral a, Floating a) => V2 a -> V2 a 

を働くあなたが代わりにあなたがする定義をlenを変更することができます

($*) :: Num a, ?b => V2 a -> b -> V2 a 

Anyayを定義しようとすることができます

LEN ::(ヌムA)=> V2 a - > a

+0

いいえ、1 ::(Num a)=> a。 – ivanm

+0

私はそれが問題のlenだと認識しました – mb14

0

どのように...

len :: (Floating a) => V2 a -> a 
len (V2 x y) = sqrt $ x * x + y * y 

normal :: (Floating a) => V2 a -> V2 a 
normal v = v *$ (1.0/len v) 

当然のことながら、換算する前にV2 Intを変換する必要があることを意味しますが、これは分割を行う前にIntを変換する必要があるようです。

+0

次に整数のベクトルを扱う能力を失います –

+0

しかし、これは通常の動作です。これは 'sqrt 4'を書くことができないのと同じです。 – Landei

+0

@Landei:これはNumクラスのfromIntegerのポイントです:整数リテラルは任意の数値型に変換できます! – ivanm

1

最小限の修正だけで、通常のために型シグネチャを変更することです:ここでは

normal :: Floating a => V2 a -> V2 a 

は種類は次のとおりです。

sqrt :: Floating a => a -> a 

だからFloating以外のものを受け入れるlenのための理由はありません。