Haskell中Functor调用incStat报错:类型变量歧义问题求助
问题分析:Functor与类型类的歧义类型错误
代码定义
-- 假设我们要创建一个能执行如下操作的Functor: -- -- fmap inc (Strength 3) data Stat a = Strength a | Agility a | Constitution a deriving Show instance Functor Stat where -- fmap :: (a -> b) -> Stat a -> Stat b fmap g (Strength str) = Strength (g str) fmap g (Agility agi) = Agility (g agi) fmap g (Constitution con) = Constitution (g con) -- 可以这样调用:fmap inc (Strength 3) -- 假设我们用类型类来实现这个函数 class Inc a where incStat :: (Num a) => a -> a instance Inc (Stat a) where incStat (Strength a) = Strength a -- instance Show a => Show (Stat a) where -- show (Strength a) = show (a) -- show (Agility a) = show (a) -- show (Constitution a) = show (a)
执行错误
执行fmap incStat (Strength 3)时触发如下错误:
<interactive>:62:1: error: • Ambiguous type variable ‘b0’ arising from a use of ‘print’ prevents the constraint ‘(Show b0)’ from being solved. Probable fix: use a type annotation to specify what ‘b0’ should be. Potentially matching instances: instance Show Ordering -- Defined in ‘GHC.Show’ instance Show a => Show (Stat a) -- Defined at characteristicsFunctor.hs:9:24 ...plus 26 others ...plus 12 instances involving out-of-scope types (use -fprint-potential-instances to see them all) • In a stmt of an interactive GHCi command: print it
错误含义与根源
这个错误的核心是GHC无法推导fmap incStat (Strength 3)返回值的具体类型,导致无法满足打印所需的Show约束。
具体原因拆解
- 类型类与实例不匹配:
你定义的Inc类要求incStat的参数和返回值是同一个Num类型,但给Stat a实现Inc实例时,incStat的参数和返回值是Stat a类型——而Stat a并没有实现Num约束,直接导致incStat的类型推导混乱。 - fmap的类型不兼容:
fmap的类型是(a -> b) -> Stat a -> Stat b,它需要一个能把a(这里是Int,因为Strength 3是Stat Int)转换成b的函数。但你的incStat实例对应的类型是Stat a -> Stat a,和fmap需要的Int -> b完全不匹配。GHC无法确定b的具体类型,自然找不到对应的Show实例来打印结果,因此抛出“歧义类型变量”错误。
修复方向
如果想通过类型类实现对Stat容器内数值的递增,应该把Inc类定义为针对容器类型的类:
class Inc f where incStat :: Num a => f a -> f a instance Inc Stat where incStat (Strength a) = Strength (a + 1) incStat (Agility a) = Agility (a + 1) incStat (Constitution a) = Constitution (a + 1)
此时直接调用incStat (Strength 3)即可得到正确结果,不需要用fmap。如果一定要用fmap,则需要一个普通的数值递增函数:
inc :: Num a => a -> a inc x = x + 1 -- 调用方式:fmap inc (Strength 3)
内容的提问来源于stack exchange,提问作者Yago
相关产品推荐
相关产品推荐

