haskell 为什么表达式'foldr(mappend.Sum)1 [2]'进行类型检查?

kr98yfug  于 2022-11-24  发布在  其他
关注(0)|答案(2)|浏览(114)

如果我β-约简下面的表达式:

foldr (mappend . Sum) 1 [2]
= (mappend . Sum) 2 (foldr (mappend . Sum) 1 [])
= (mappend . Sum) 2 1
= mappend (Sum 2) 1
...

望式:

// mappend (<>) :: Monoid a => a -> a -> a

我们可以看到最后一行有一个类型错误,因为常量1应该属于Monoid类(而它没有)。
然而,ghci并没有抱怨。
为什么该表达式类型检查?

7gs2gvoe

7gs2gvoe1#

简短回答1被解释为Sum a,因此文件夹的类型为:

foldr (mappend . Sum) 1 [2] :: Num a => Sum a

其中2具有类型a,并且1具有类型Sum a

**Sum a**是Num的一个示例如果aNum的一个示例,实际上,源代码是[src]:

newtype Sum a = Sum { getSum :: a }
        deriving ( Eq       -- ^ @since 2.01
                 , Ord      -- ^ @since 2.01
                 , Read     -- ^ @since 2.01
                 , Show     -- ^ @since 2.01
                 , Bounded  -- ^ @since 2.01
                 , Generic  -- ^ @since 4.7.0.0
                 , Generic1 -- ^ @since 4.7.0.0
                 , Num      -- ^ @since 4.7.0.0
                 )

这意味着如果你写一个整数字面值,比如1,它可以被构造为Sum a,对于任何a,它是Num的一个示例,所以1 :: Sum IntegerSum 1
因此,这意味着foldr中的1具有Sum a类型,因此例如:

mappend (Sum 2 :: Sum Integer) (1 :: Sum Integer)
-> Sum (2 + 1)
-> Sum 3
bqucvtff

bqucvtff2#

在Sum类型的文档中,您可以找到以下指示示例:

Num a => Num (Sum a)

(当然,它应该在那里是完全合理的--不仅Sum aa "在道德上是相同的类型",而且Sum显然被设计为几乎只与数字类型一起使用)。
因为Haskell中的数值型文字(如1)可以是Num类的任何类型的示例,所以mappend (Sum 2) 1中没有类型错误,因为编译器会自动将其有效地转换为mappend (Sum 2) (Sum 1)(因为在Sum aNum示例中,fromInteger 1将是Sum 1)。

相关问题