Haskell中局部值变量类型为何会影响函数签名的输入变量类型?
问题对应的代码示例
Prelude> func f = [(show s, f == s) | s <- [0, 1..10]] Prelude> :type func func :: (Num a, Enum a, Show a, Eq a) => a -> [(String, Bool)]
核心原因
这是Haskell类型系统的同类型匹配规则和自动类型推导的必然结果,本质和“局部变量”无关,而是由你代码中隐含的「f和s必须是同一类型」的要求决定的。
具体推导逻辑
- 首先Haskell中相等运算符
==的签名是Eq a => a -> a -> Bool,强制要求左右两个操作数必须是完全相同的类型,所以你写f == s时,编译器会直接判定f和s的类型完全等价。 - 再看代码中
s本身带的类型约束:- 列表推导式里
s <- [0, 1..10]:0/1这类字面量属于多态的Num类型值,..枚举语法要求元素实现Enum类型类,因此s必须满足Num a、Enum a约束 - 你调用了
show s将s转为字符串,因此s还需要满足Show a约束 - 加上
==本身要求的Eq a约束,s总共需要满足4个类型类约束
- 列表推导式里
- 因为之前已经推导出
f和s类型完全等价,所以s需要满足的所有约束,f也必须全部满足,最终func的类型就带上了这4个约束。
两种特殊情况的解释
- 若将相等判断中的s替换为其他和f无关联的值,f的约束就仅剩下Eq a:只要
==的右侧不再是s,且右侧值没有额外的类型类约束、也不需要和s同类型,那么f就只需要满足==要求的Eq a约束,和s的约束完全解耦。 - 若将等式中的s替换为任意常量,f对应的相关类型约束就会消失:如果
s不再出现在f == x的判断里,f和s就没有了同类型绑定,s的Num/Enum/Show约束自然不会再传递给f。
内容的提问来源于stack exchange,提问作者Anon
相关产品推荐
相关产品推荐

