为何这段Haskell代码会被判定为类型不匹配错误?
解决Haskell类型不匹配错误
先看看你的原代码:
import Prelude hiding (div) data Expr = Expr Op Int Int deriving (Show) data Op = Add | Sub | Mul | Div deriving (Show) evaluate :: (Num a) => Expr -> a evaluate (Expr Add a b) = a + b --evaluate (Expr Sub a b) = sub a b --evaluate (Expr Mul a b) = mul a b --evaluate (Expr Div a b) = div a b
对应的错误提示:
exprs.hs:8:27: error:
• 无法匹配预期类型‘a’与实际类型‘Int’
‘a’是由……绑定的刚性类型变量的内容
错误原因拆解
这个问题核心是类型签名和实际代码的类型不匹配:
- 你给
evaluate的签名是(Num a) => Expr -> a,意思是这个函数可以返回任意实现了Num类型类的类型(比如Int、Integer、Float都可以),这个a是由调用函数的地方决定的,属于“刚性类型变量”——函数自己不能随便固定它的类型。 - 但你的
Expr数据结构里,存储的是固定的Int值,当你计算a + b时,Haskell会推断这个结果的类型是Int,这就和签名里要求的任意a冲突了,所以类型系统直接报错。
两种修复方案
方案1:保持Expr存储Int,适配类型签名
如果你的表达式就是要处理整数,有两种选择:
- 把
evaluate的返回类型固定成Int,这样类型完全匹配:
import Prelude hiding (div) data Expr = Expr Op Int Int deriving (Show) data Op = Add | Sub | Mul | Div deriving (Show) evaluate :: Expr -> Int evaluate (Expr Add a b) = a + b evaluate (Expr Sub a b) = a - b evaluate (Expr Mul a b) = a * b evaluate (Expr Div a b) = div a b
- 或者用
fromIntegral把Int转换成任意Num类型,这样依然支持灵活的返回类型:
import Prelude hiding (div) data Expr = Expr Op Int Int deriving (Show) data Op = Add | Sub | Mul | Div deriving (Show) -- 加减乘用Num约束即可 evaluate :: (Num a) => Expr -> a evaluate (Expr Add a b) = fromIntegral a + fromIntegral b evaluate (Expr Sub a b) = fromIntegral a - fromIntegral b evaluate (Expr Mul a b) = fromIntegral a * fromIntegral b -- 除法需要Fractional约束(因为Num不包含除法操作) evaluate :: (Fractional a) => Expr -> a evaluate (Expr Div a b) = fromIntegral a / fromIntegral b
方案2:把Expr改成多态类型,支持任意数字
如果希望你的表达式能处理不同类型的数字(比如整数、浮点数),可以把Expr定义成多态数据结构:
import Prelude hiding (div) -- 这里的a代表任意类型,后续可以是Int、Float等 data Expr a = Expr Op a a deriving (Show) data Op = Add | Sub | Mul | Div deriving (Show) -- 加减乘支持任意Num类型 evaluate :: (Num a) => Expr a -> a evaluate (Expr Add a b) = a + b evaluate (Expr Sub a b) = a - b evaluate (Expr Mul a b) = a * b -- 除法需要Fractional约束 evaluate :: (Fractional a) => Expr a -> a evaluate (Expr Div a b) = a / b
这样你可以创建Expr Int或者Expr Float类型的表达式,evaluate会根据输入的类型返回对应类型的结果。
内容的提问来源于stack exchange,提问作者corecase
相关产品推荐
相关产品推荐

