我有以下代码片段:
Prelude Data.Monoid> :t 1 <> (2 :: Sum Integer)
1 <> (2 :: Sum Integer) :: Sum Integer
Run Code Online (Sandbox Code Playgroud)
怎么1变成Sum Integer打字?
更新
我玩了一下mappend功能并发现:
Prelude Data.Monoid> x = mappend 43
Run Code Online (Sandbox Code Playgroud)
为什么mappend会接受这个号码43?43是一个Num类型,它没有monoid实例.
首先(2 :: Sum Integer).
Haskell中的任何文字整数都由Haskell通过将其包装在fromInteger调用中来重写.所以:
(2 :: Sum Integer) == ((fromInteger (2 :: Integer)) :: Sum Integer)
Run Code Online (Sandbox Code Playgroud)
Haskell只允许左侧的符号,因此更容易键入,但它相当于右侧的代码.
该fromInteger函数具有以下类型签名:
fromInteger :: Num a => Integer -> a
Run Code Online (Sandbox Code Playgroud)
因此,(fromInteger (2 :: Integer))具有类型Num a => a
在库中的某个位置,您将拥有如下所示的实例:
instance Num a => Num (Sum a) where ...
Run Code Online (Sandbox Code Playgroud)
由于Integer是一个Num,所以是Sum Integer.
因此,我们可以转换Num a => a到Sum Integer代刚a = Sum Integer.
最后,我们有这个Semigroup功能:
(<>):: Semigroup a => a - > a - > a
还有一个例子:
instance Num a => Semigroup (Sum a) where ...
Run Code Online (Sandbox Code Playgroud)
在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实例,所以应该编译好.