You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何表达式`foldr (mappend . Sum) 1 [2]`能通过类型检查?

为什么foldr (mappend . Sum) 1 [2]能通过类型检查?

你手动β归约时的问题出在对初始值1的类型理解上——Haskell的整数字面量是多态的,它的类型不是固定的Integer,而是Num a => a。当上下文要求它是某个Num实例类型时,会自动通过Num类的fromInteger函数完成转换。

我们一步步拆解类型推导过程:

  1. 先明确foldr的类型:

    foldr :: (a -> b -> b) -> b -> [a] -> b
    
  2. 分析第一个参数mappend . Sum的类型:

    • Sum的类型是Sum :: a -> Sum a
    • mappend的类型是Monoid m => m -> m -> m
    • 组合后的mappend . Sum类型为Num a => a -> Sum a -> Sum a(因为Sum的Monoid实例要求底层类型a属于Num,mappend对应加法操作)
  3. 结合第三个参数[2](默认元素类型为Integer),可以推导出:

    • foldr中的a是Integer
    • 函数mappend . Sum的输出类型是Sum Integer,因此foldr的b类型必须是Sum Integer
  4. 初始值1的类型被上下文约束为Sum Integer:
    因为Sum a在a是Num时本身也是Num实例(Haskell为Sum自动派生了Num实例),所以整数字面量1会被自动转换为Sum (fromInteger 1),也就是Sum 1。

你手动归约时把foldr (mappend . Sum) 1 []直接写成了原始整数1,但实际上GHC处理时,这个初始值已经是Sum 1了。正确的归约流程应该是:

foldr (mappend . Sum) 1 [2]
= (mappend . Sum) 2 (foldr (mappend . Sum) 1 [])
= (mappend . Sum) 2 (Sum 1)  -- 这里初始值是Sum 1,不是Integer 1
= mappend (Sum 2) (Sum 1)
= Sum (2 + 1)
= Sum 3

这样就完全符合mappend的类型要求(两个Sum Integer参数),自然不会有类型错误。

内容的提问来源于stack exchange,提问作者F. Zer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 04:45:30