2015-07-19 45 views
0

我有這種類型的類。但它不能推斷從goal返回的類型等於isGoal的第一個變量的類型。如何解決這個問題?無法從上下文推斷

{-# LANGUAGE TypeFamilies, FlexibleContexts #-} 
class Problem p where 
    type State p :: * 
    data Action p :: * 

    goal :: Eq (State p) => State p 
    goal = undefined 

    isGoal :: Eq (State p) => State p -> Bool 
    isGoal s = s == goal 

結束了做這個

class Problem p where 
    type State p :: * 
    data Action p :: * 

    goal :: p -> State p 
    goal = undefined 

    isGoal :: Eq (State p) => p -> State p -> Bool 
    isGoal p s = s == goal p 
+2

這將是很好,如果你在一些其他的方式來呈現錯誤消息。從Windows控制檯的屏幕截圖,認真... – leftaroundabout

+0

它沒有意識到你正在嘗試使用來自同一實例的'goal'。 – melpomene

+0

@leftaroundabout從Windows控制檯複製和粘貼非常煩人,我可以理解,寧願截取屏幕截圖。 –

回答

8

的提示是正確的,在錯誤消息:

注: '國家' 是一種功能,並且可能不內射

這是什麼意思S:一個injective function˚F是其中來自˚FX)= ˚FÝ)它遵循X = ý的功能。現在,我們在這裏討論類型級別,所以如果State是內射的,那麼將從State p ~ State q那裏得到p ~ q

s == goal,編譯器知道它需要統一goals(因爲==總是比較相同類型的值),所以我們有它:

s :: State p 
goal :: State q 
State p ~ State q 

但由於State射,編譯器不能推斷出p ~ q,也就是說我們只是在談論類型類的單個實例。

爲什麼不呢?那麼,你能想出:

instance Problem Int where 
    type State Int = Bool 
    goal = True 

instance Problem Double where 
    type State Double = Bool 
    goal = False 

現在我們有State Int ~ State Double。然而,顯然IntDouble不是相同的類型,它們以相互矛盾的方式定義goal


「如何解決這個」 –好,你需要重新設計的類。

  • 您可以使用

    class Problem p where 
        data State p :: * 
    

    在這種情況下,State射,因爲每個實例必須是硬烘烤成單一instance Problem

  • 如果您需要在別處定義實際State類型的能力,你需要給編譯器,p應該用於goal明確的提示。通常的解決辦法是代理或– preferrable IMO – tagged值:

    {-# LANGUAGE ScopedTypeVariables #-} 
    import Data.Tagged 
    
    class Problem p where 
        type State p :: * 
    
        goal :: Eq (State p) => Tagged p (State p) 
        goal = Tagged undefined 
    
        isGoal :: Eq (State p) => Tagged p (State p) -> Bool 
        isGoal = isGoalDef 
    
    isGoalDef :: forall p . Eq (State p) => Tagged p (State p) -> Bool 
    isGoalDef (Tagged s) = s == g 
        where (Tagged g) = goal :: Tagged p (State p)