2014-10-04 32 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' ...。但我想這是另一個問題,所以我認爲這個答案。謝謝。