我有以下代码段:
Prelude Data.Monoid> :t 1 <> (2 :: Sum Integer)
1 <> (2 :: Sum Integer) :: Sum Integer
1
如何成为Sum Integer
类型?
更新
我使用mappend
功能玩了一下并发现:
Prelude Data.Monoid> x = mappend 43
为什么mappend接受号码43
? 43
是Num
类型,它没有monoid实例。
答案 0 :(得分:5)
首先(2 :: Sum Integer)
。
Haskell中的任何文字整数都由Haskell通过将其包装在fromInteger
调用中来重写。所以:
(2 :: Sum Integer) == ((fromInteger (2 :: Integer)) :: Sum Integer)
Haskell只允许左侧的符号,因此更容易输入,但它等同于右侧的代码。
fromInteger
函数具有以下类型签名:
fromInteger :: Num a => Integer -> a
因此(fromInteger (2 :: Integer))
的类型为Num a => a
在图书馆的某个地方,您将拥有如下所示的实例:
instance Num a => Num (Sum a) where ...
由于Integer
是Num
,因此Sum Integer
。
因此我们只需替换Num a => a
即可将Sum Integer
转换为a = Sum Integer
。
最后,我们有Semigroup
函数:
(&lt;&gt;):: Semigroup a =&gt; a - &gt; a - &gt;一个
还有一个例子:
instance Num a => Semigroup (Sum a) where ...
在semigroups模块中的某个地方,并且(<>)
函数指定左右参数和结果必须是相同的参数,那么如果我们知道其中一个,我们就知道其他两个。我们知道正确的参数是Sum Integer
,所以我们必须检查我们是否可以将左参数转换为Sum Integer
。
从以前开始,1
确实意味着fromInteger (1 :: Integer)
。我们之前已经提到了fromInteger
Sum Integer
的实现,所以这很好。然后我们可以对它们使用半群操作(<>)
,因为它们现在是同一类型,也是Semigroup
。
回复更新
Num
不是一个类型,它是一个类。 Integer
是一种类型,但正如我之前所说,43
不是Integer
,而是fromInteger 43
。它可以是Integer
,也可以是任何Num
类型。其中一些Num
类型可能是Monoid
。
尝试使用x = mappend (43 :: Integer)
,您现在发现代码无法编译,因为您强制Num
成为Int
而不是Monoid
x = mappend (43 :: Sum Integer)
个实例。
但是,Monoid
确实有一个{{1}}实例,所以编译得很好。