2014-10-04 37 views
2

我有一个类型的类GHC:为什么输入歧义走开使用让

class (Monad f) => Test f where 
    test ::() -> f() 

和实例

instance Test (ErrorT String (Identity)) where 
    test pat = return pat 

如果我运行一个单子栈参照本实例时,GHC可以”找不到什么单子我说的(在Either String单子的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规则?)在这里我不理解?

我使用的扩展MultiParamTypeClassesFlexibleInstancesScopedTypeVariables

编辑:我简单的例子,从而出现奇怪的问题,而不需要我的代码的其余部分(以及更短的单子栈),但现在它看起来荒谬。该语句的完整的上下文是:

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 
+3

你能把这个减少到一个小的可重复的例子吗?这个代码中有太多的外部事物可以自己尝试 - 例如'Pattern','Symbol','g'和'rhs'。 – 2014-10-04 17:43:34

+1

我认为在你的cutdown代码中,如果你不使用'action',那么'let action = test rhs'就会产生歧义。如果我使用'test rhs'并且删除'let action ='行,它编译得很好。 – 2014-10-04 18:34:17

+0

另外,假设这不是你原来的代码的问题,如果你不使用'$',即写'runIdentity(runErrorT(test rhs))'',会发生什么?这只是一个猜测,但在某些时候,有一些有趣的规则可以帮助'运行'...'类型检查,这只是可能的。 – 2014-10-04 18:39:10

回答

2

代码

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或单态限制启用,除非类型是已知的,防止结合的推广到action

+0

解释它。虽然它仍然不能解释为什么在我的原始代码中(有一个类型变量),我无法给'action'赋予一个类型签名。我有'ScopedTypeVariables'启用,但我得到关于刚性类型变量的典型错误消息。 – 2014-10-06 13:31:51

0

看来,单态限制让我感到沮丧,以及在两个版本之间切换时,我在代码中留下了未使用的绑定这一事实(我认为我没有,也没关系,但它确实)。所以action的类型不能推断为单形类型。

仍然存在一个问题:在我原来的代码中,我使用了一个多态类型(Pattern s)无处不在,你现在看到的是()。编译器在错误消息中建议我为action添加一个类型签名以修复多态性,但令人困惑的是我不能:即使使用ScopedTypeVariables,我也会收到有关runaction的类型签名中绑定的刚性类型变量的错误消息Couldn't match type 's1' with 's3' ...。但我想这是另一个问题,所以我认为这个答案。谢谢。

相关问题