我有一个类型类
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
block 中) ):
rhs' <- runIdentity $ runErrorT $ test rhs
产生错误消息:
Ambiguous type variable `f0' in the constraint:
(Test f0) arising from a use of `test'
...
但是如果我将 test rhs
部分绑定(bind)到变量:
let action = test rhs
rhs' <- runIdentity $ runErrorT $ action
它有效,即使该变量没有在其他地方使用,因此无法推断出任何新内容。
如果我没有添加类型检查器要使用的信息,这怎么可能?为什么它无法找出等效的第一个公式的类型?或者这两个公式不等价? Haskell 类型检查器(或脱糖规则?)的哪一部分我不明白?
我正在使用扩展 MultiParamTypeClasses
、FlexibleInstances
和 ScopedTypeVariables
编辑:我简化了示例,因此奇怪的问题发生时不需要我的代码的其余部分(并且具有更短的单子(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
类型检查应该没有问题。问题是
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 或单态限制,这会阻止绑定(bind)到 action
的泛化,除非类型已知。
关于haskell - GHC : Why does type ambiguity go away when using let,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26195242/