为什么总和需要GHC.Num.fromInteger?
why does sum need GHC.Num.fromInteger?
我有一个定义为 3 个浮点数的 3d 矢量数据类型。我知道如果我为我的 class 提供一个 Num
实例并定义正常的数学运算符,我就可以在我的 class 上使用它们。
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)
当我将我的文件加载到 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.
但是,我仍然可以使用我定义的那些。
*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}
我的困惑来自于我在尝试使用求和函数时遇到的以下错误
*Main> sum [a,b]
Vec3 {x = *** Exception: temp.hs:6:10-17: No instance nor default method for class operation GHC.Num.fromInteger
为什么 sum 需要 fromInteger
定义我的 Vec3
数据类型?一方面,我认为 sum 只使用 +
函数,另一方面,我的数据类型不使用 Integer
.
下面是 sum 的实现方式:
sum = foldl (+) 0
注意 0
文字。让我们在 GHCi 中检查它的类型:
λ> :t 0
0 :: Num a => a
事实证明,数字文字是 fromInteger
的糖分。即 0
实际上是 fromInteger 0
.
因此,sum
需要fromInteger
,因为上面的定义是糖:
sum = foldl (+) (fromInteger 0)
fromInteger
的实现很简单:
instance Num Vec3 where
fromInteger n = let a = (fromInteger n) in Vec3 a a a
此外,我强烈建议在创建实例时,始终完整定义它,以避免出现此类不可预见的麻烦。
sum [] :: Vec3
return应该怎么办?
sum
函数可以定义为
sum :: (Num a) => [a] -> a
sum = foldl (+) 0
0
实际上是fromInteger (0 :: Integer)
,所以你需要fromInteger
才能使用sum
。
其实在base-4.8中sum
是根据Sum
Monoid
和Foldable
定义的,但这是不同的故事。你仍然需要fromInteger (0 :: Integer)
。
我有一个定义为 3 个浮点数的 3d 矢量数据类型。我知道如果我为我的 class 提供一个 Num
实例并定义正常的数学运算符,我就可以在我的 class 上使用它们。
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)
当我将我的文件加载到 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.
但是,我仍然可以使用我定义的那些。
*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}
我的困惑来自于我在尝试使用求和函数时遇到的以下错误
*Main> sum [a,b]
Vec3 {x = *** Exception: temp.hs:6:10-17: No instance nor default method for class operation GHC.Num.fromInteger
为什么 sum 需要 fromInteger
定义我的 Vec3
数据类型?一方面,我认为 sum 只使用 +
函数,另一方面,我的数据类型不使用 Integer
.
下面是 sum 的实现方式:
sum = foldl (+) 0
注意 0
文字。让我们在 GHCi 中检查它的类型:
λ> :t 0
0 :: Num a => a
事实证明,数字文字是 fromInteger
的糖分。即 0
实际上是 fromInteger 0
.
因此,sum
需要fromInteger
,因为上面的定义是糖:
sum = foldl (+) (fromInteger 0)
fromInteger
的实现很简单:
instance Num Vec3 where
fromInteger n = let a = (fromInteger n) in Vec3 a a a
此外,我强烈建议在创建实例时,始终完整定义它,以避免出现此类不可预见的麻烦。
sum [] :: Vec3
return应该怎么办?
sum
函数可以定义为
sum :: (Num a) => [a] -> a
sum = foldl (+) 0
0
实际上是fromInteger (0 :: Integer)
,所以你需要fromInteger
才能使用sum
。
其实在base-4.8中sum
是根据Sum
Monoid
和Foldable
定义的,但这是不同的故事。你仍然需要fromInteger (0 :: Integer)
。