Haskell中Either类型模式匹配报错原因咨询
Haskell Either类型模式匹配的类型不匹配问题解析
问题核心
为什么patternMaster函数中单独实现(Right a)分支时看似没问题,但补全Left分支后会触发类型不匹配错误?同时对比evalErr的正确写法,两者的本质差异是什么?
错误代码与报错信息
错误代码
patternMaster :: Either a b -> b patternMaster (Right a) = a patternMaster (Left b) = b
报错信息
Arithmetic.hs:101:26: error: * Couldn't match expected type `b' with actual type `a' `a' is a rigid type variable bound by the type signature for: patternMaster :: forall a b. Either a b -> b at Arithmetic.hs:99:1-32 `b' is a rigid type variable bound by the type signature for: patternMaster :: forall a b. Either a b -> b at Arithmetic.hs:99:1-32 * In the expression: b In an equation for `patternMaster': patternMaster (Left b) = b * Relevant bindings include b :: a (bound at Arithmetic.hs:101:21) patternMaster :: Either a b -> b (bound at Arithmetic.hs:100:1)
参考正确代码
-- -----------类型定义 initEnvironment :: Env initEnvironment = \_v -> Nothing -- --------求值函数 evalErr :: Exp -> Env -> Either ArithError Integer evalErr (Cst e1) _ = Right e1 evalErr (Div e1 e2) env = case evalErr e2 env of Left az -> Left az Right az -> if az == 0 then Left EDivZero else case (evalErr e1 env) of Left b -> Left b Right b -> Right (b `div` az)
原因分析
1. patternMaster的类型矛盾
patternMaster的类型签名Either a b -> b要求:无论输入是Left a还是Right b,函数必须返回类型为b的值。但问题出在Left分支:
- 当匹配
Left b时,这里的变量b(注意和类型参数b重名,容易混淆)实际属于类型a - Haskell的类型系统中,
a和b是完全独立的多态类型变量,没有任何约束能保证a类型的值可以转换成b类型,因此直接返回b会触发类型不匹配错误。
单独写Right分支时,只是因为没有触发Left分支的类型检查,Haskell只会提示非穷尽模式警告,不会立刻报错,但这个函数从一开始就不符合类型系统的要求。
2. evalErr的类型一致性
evalErr的返回类型是Either ArithError Integer,它的每个分支都严格遵循这个类型:
- 匹配
Left az时,az是ArithError类型,返回Left az正好是Either ArithError Integer类型 - 匹配
Right az时,后续逻辑要么返回Left EDivZero(ArithError类型的构造器),要么返回Right (bdivaz)(Integer类型),所有分支的返回值都是同一个Either类型的合法实例,完全符合类型签名要求。
两者本质差异
patternMaster试图将Either的两个不同类型分支(a和b)统一成单一类型b返回,违背了Haskell的多态类型约束evalErr则是在Either的同一类型框架内处理分支:所有分支都返回Either ArithError Integer类型,只是选择不同的构造器填充对应类型的值,完全符合类型系统规则
内容的提问来源于stack exchange,提问作者Piskator
相关产品推荐
相关产品推荐

