Haskell中StateT的Functor实例实现报错:无法推导Functor k1的问题排查与解决
Haskell中StateT的Functor实例实现报错:无法推导Functor k1的问题排查与解决
嘿,我来帮你搞定这个报错问题~
问题原因分析
你手动给<$>加上的forall k a b s.类型签名是“搞事情”的根源!
在instance Functor k => Functor (StateT s k)这个声明里,我们已经限定了k是一个Functor。但你手动写的forall重新引入了一套全新的类型变量——这里的k和instance上下文里的k不是同一个东西!编译器把它当成了k1(一个完全陌生的类型),自然找不到它的Functor约束,所以就抛出了那个“无法推导Functor k1”的错误。
解决办法
最简单的修复方式就是删掉手动添加的forall和对应的类型签名,让Haskell的类型推导自动处理:
instance Functor k => Functor (StateT s k) where (<$>) f st1 = StateT $ \s -> mapFunc <$> (runStateT st1 s) where mapFunc :: (a, s) -> (b, s) mapFunc = \(a, s) -> (f a, s)
如果你确实想显式写出类型签名(比如为了可读性),那要确保forall绑定的类型变量和instance的完全一致,并且只对需要泛化的变量做绑定:
instance Functor k => Functor (StateT s k) where (<$>) :: forall a b. (a -> b) -> StateT s k a -> StateT s k b (<$>) f st1 = StateT $ \s -> mapFunc <$> (runStateT st1 s) where mapFunc :: (a, s) -> (b, s) mapFunc = \(a, s) -> (f a, s)
这里我们只对a和b做forall绑定,s和k沿用instance声明里的变量,这样编译器就能正确识别到k已经带有Functor约束了。
验证修复效果
现在再运行你给的测试用例:
runStateT ((+1) <$> (pure 2) :: StateT Int List Int) 0
应该能正常返回[(3,0)]啦~
备注:内容来源于stack exchange,提问作者zichao liu
相关产品推荐
相关产品推荐

