【问题标题】:Why does the expression `foldr (mappend . Sum) 1 [2]` type checks?为什么表达式 `foldr (mappend . Sum) 1 [2]` 会进行类型检查?
【发布时间】:2022-11-21 05:58:38
【问题描述】:

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

  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 并没有抱怨。

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

【问题讨论】:

  • 了解术语的类型至关重要,两个数字文字是不是同一类型: foldr ((&lt;&gt;) . Sum) (1 :: Sum Int) [2 :: Int]
  • 是的当然。对我来说,两种数字文字都有不同的类型。

标签: haskell


【解决方案1】:

简答: 1 被解释为 Sum a,所以你的文件夹类型是:

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

其中2 的类型为a1 的类型为Sum a

Sum aNum 的一个实例,如果aNum 的一个实例,确实是the source code says [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对于任何aNum的一个实例,所以1 :: Sum IntegerSum 1

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

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

【讨论】:

    【解决方案2】:

    documentation for the Sum type 中,您会发现这个说明性实例:

    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。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-24
      相关资源
      最近更新 更多