我有一个类型类
class (Monad f) => Test f where
test :: () -> f ()
和一个实例
instance Test (ErrorT String (Identity)) where
test pat = return pat
如果我运行一个引用此实例的monad堆栈,GHC无法找到我所说的monad(在Either String
monad的do
块中):
rhs' <- runIdentity $ runErrorT $ test rhs
产生错误消息:
Ambiguous type variable `f0' in the constraint:
(Test f0) arising from a use of `test'
...
但如果我将部分test rhs
绑定到一个变量:
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
它是有效的,即使这个变量没有在其他地方使用,所以不能推断出任何新的信息
如果我没有添加任何信息供类型检查器使用,这怎么可能呢?为什么它不能计算出等效的第一个公式的类型?还是这两种表述不对等?我在这里不理解Haskell类型检查器(或desugaring规则?)的哪些部分?
我正在使用扩展MultiParamTypeClasses
、FlexibleInstances
和ScopedTypeVariables
edit:我简化了这个例子,所以这个奇怪的问题在不需要我的其余代码的情况下发生(并且使用了更短的monad堆栈),但现在它看起来毫无意义。声明的完整上下文是:
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
let action = test rhs
rhs' <- runIdentity $ runErrorT $ test rhs -- or: action
return g
代码
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
rhs' <- runIdentity $ runErrorT $ test rhs
return g
或
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
return g
应键入check而不会出现问题。问题是
doStuff :: (Map Int ()) -> Either String (Map Int ())
doStuff g = run (snd . head . Map.toList $ g) g where
run :: () -> Map Int () -> Either String (Map Int ())
run rhs g = do
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
return g
原因是您似乎启用了MonoLocalBinds或单态性限制,除非类型已知,否则它会阻止绑定到action
的泛化。
单态性限制似乎让我绊倒了,再加上我在两个版本之间切换时在代码中留下了未使用的绑定(我以为我没有,也没关系,但确实如此)。因此CCD_ 8的类型不能归结为单态类型。
仍然有一个悬而未决的问题:在我的原始代码中,无论您现在看到()
,我都使用多态类型(Pattern s)
。编译器在错误消息中建议我为action
添加一个类型签名来修复多态性,但令人困惑的是,我不能:即使使用了ScopedTypeVariables
,我也得到了关于绑定在run
和action
的类型签名中的刚性类型变量的错误消息Couldn't match type 's1' with 's3' ...
。但我想这是另一个问题,所以我认为这个问题已经得到了回答。非常感谢。