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

F. *_*Zer 2 haskell

如果我对以下表达式进行 beta-reduce:

  foldr (mappend . Sum) 1 [2]
= (mappend . Sum) 2 (foldr (mappend . Sum) 1 [])
= (mappend . Sum) 2 1
= mappend (Sum 2) 1
...
Run Code Online (Sandbox Code Playgroud)

查看类型:

// mappend (<>) :: Monoid a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

我们可以看到最后一行有一个类型错误,因为常量1应该属于Monoid类(但事实并非如此)。

不过,ghci并不抱怨。

为什么要检查表达式类型?

Wil*_*sem 5

简短回答1被解释为 a Sum a,因此您的foldr 的类型是:

foldr (mappend . Sum) 1 [2] :: Num a => Sum a
Run Code Online (Sandbox Code Playgroud)

其中2has typea1has type Sum a

Sum a是一个实例Numifa是一个实例Num,事实上,源代码显示 [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
                 )
Run Code Online (Sandbox Code Playgroud)

因此,这意味着如果您编写一个整数文字,例如1,它可以被构造为Sum a任何 的a实例Num,因此1 :: Sum Integer也是Sum 1

因此,这意味着1您的foldr具有 type Sum a,因此例如:

   mappend (Sum 2 :: Sum Integer) (1 :: Sum Integer)
-> Sum (2 + 1)
-> Sum 3
Run Code Online (Sandbox Code Playgroud)