为什么总和需要GHC.Num.fromInteger?

use*_*829 6 haskell ghc

我有一个3d矢量数据类型定义为3个浮点数.我明白如果我Num为我的类提供一个实例并定义普通的数学运算符,我可以在我的课上使用它们.

data Vec3 = Vec3 { x :: Float
                 , y :: Float
                 , z :: Float
                 } deriving (Show, Eq)

instance Num Vec3 where
  (+) v1 v2 = Vec3 (x v1 + x v2) (y v1 + y v2) (z v1 + z v2)
Run Code Online (Sandbox Code Playgroud)

当我将文件加载到ghci时,我收到警告,因为我没有定义所有函数Num,这是有道理的.

Prelude> :l temp.hs
[1 of 1] Compiling Main             ( temp.hs, interpreted )

temp.hs:6:10: Warning:
    No explicit method or default declaration for `*'
    In the instance declaration for `Num Vec3'

temp.hs:6:10: Warning:
    No explicit method or default declaration for `abs'
    In the instance declaration for `Num Vec3'

temp.hs:6:10: Warning:
    No explicit method or default declaration for `signum'
    In the instance declaration for `Num Vec3'

temp.hs:6:10: Warning:
    No explicit method or default declaration for `fromInteger'
    In the instance declaration for `Num Vec3'
Ok, modules loaded: Main.
Run Code Online (Sandbox Code Playgroud)

但是,我仍然可以使用我定义的那些.

*Main> let a = Vec3 1.0 2.0 3.0
*Main> let b = Vec3 2.0 4.0 5.0
*Main> a + b
Vec3 {x = 3.0, y = 6.0, z = 8.0}
Run Code Online (Sandbox Code Playgroud)

我的困惑来自于我在尝试使用sum函数时得到的以下错误

*Main> sum [a,b]
Vec3 {x = *** Exception: temp.hs:6:10-17: No instance nor default method for class operation GHC.Num.fromInteger
Run Code Online (Sandbox Code Playgroud)

为什么sum需要fromInteger我的Vec3数据类型的定义?首先,我会想到sum只使用该+函数,而另一种,我的数据类型不使用 Integer.

AJF*_*mar 9

以下是总和的实现方式:

sum = foldl (+) 0
Run Code Online (Sandbox Code Playgroud)

请注意0文字.让我们检查它在GHCi中的类型:

?> :t 0
0 :: Num a => a
Run Code Online (Sandbox Code Playgroud)

事实证明,数字文字是糖fromInteger.即,0实际上是fromInteger 0.

因此,sum需要fromInteger,因为上面的定义是糖:

sum = foldl (+) (fromInteger 0)
Run Code Online (Sandbox Code Playgroud)

实施fromInteger很容易:

instance Num Vec3 where
    fromInteger n = let a = (fromInteger n) in Vec3 a a a
Run Code Online (Sandbox Code Playgroud)

此外,我强烈建议,每当制作一个实例时,总是完全定义它以避免像这样的无法预料的麻烦.