使用数字类型类型键入错误

时间:2011-11-09 09:59:20

标签: haskell

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)

-}

我无法实现上述正常功能。怎么能让它通过类型检查?

4 个答案:

答案 0 :(得分:4)

三个选项:

  • 更改您的类型签名:

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

    然后指定一个函数将(Integral a) => V2 a转换为(Floating b) => V2 b并将其应用于v之前的*$

  • Floating结果从1 / len v转换为Integral值(round等)。

  • 按照Landei的建议并强制在任何地方使用Floating

len接收(Integral a) => V2 a并返回(Floating b) => b。然后,您对结果执行1 /,结果仍为(Floating b) => b类型。从您的*$类型开始,它需要V2 aa,但在这种情况下,您的v :: (Integral a) => V2 a(1 / len v) :: (Floating b) => b不是等效类型。

所以你必须在某个地方做某种形式的强制

答案 1 :(得分:1)

最小修复只是更改普通的类型签名:

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

以下是类型:

sqrt :: Floating a => a -> a

所以len没有理由接受Floating以外的其他内容。

答案 2 :(得分: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。

答案 3 :(得分:-1)

找到它。当len返回浮动时,需要在normal中浮动。除此以外 你可以尝试定义

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

Anyay

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

作品

您也可以将len定义更改为

len ::(Num a)=> V2a - >一个