2010-11-17 103 views
5

我想要表示加權邊緣。我最終希望將OutE作爲Eq和Ord的一個實例,約束條件是etype是Eq和Ord的一個實例。假設我有以下文件temp.hs:將類型約束添加到Haskell中實例聲明的上下文中

data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype} 

applyFunBy accessor ordfun = (\x y -> (ordfun (accessor x) (accessor y))) 

instance Eq (OutE vtype etype) where 
    --(==) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool 
    --(/=) :: Ord etype => (OutE vtype etype) -> (OutE vtype etype) -> Bool 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

,當我在ghci中加載此,我得到以下錯誤:

temp.hs:10:19: 
    Could not deduce (Ord etype) 
     from the context (Eq (OutE vtype etype)) 
     arising from a use of `edgeValue' at temp.hs:10:19-27 
    Possible fix: 
     add (Ord etype) to the context of the instance declaration 
    In the first argument of `applyFunBy', namely `edgeValue' 
    In the expression: applyFunBy edgeValue (==) 
    In the definition of `==': == = applyFunBy edgeValue (==) 

temp.hs:11:19: 
    Could not deduce (Ord etype) 
     from the context (Eq (OutE vtype etype)) 
     arising from a use of `edgeValue' at temp.hs:11:19-27 
    Possible fix: 
     add (Ord etype) to the context of the instance declaration 
    In the first argument of `applyFunBy', namely `edgeValue' 
    In the expression: applyFunBy edgeValue (/=) 
    In the definition of `/=': /= = applyFunBy edgeValue (/=) 
Failed, modules loaded: none. 

如果包括的類型簽名行(==)和(\ =),我得到:

temp.hs:6:1: 
    Misplaced type signature: 
    == :: 
     (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool 

temp.hs:7:1: 
    Misplaced type signature: 
    /= :: 
     (Ord etype) => (OutE vtype etype) -> (OutE vtype etype) -> Bool 

回答

5

您有限etype是在OutE把定義Ord

data (Ord etype) => OutE vtype etype = ... 

但在Eq情況下,你實際上是試圖定義實例任何etype不受限制。

instance Eq (OutE vtype etype) where 

當然,這並不工作,因爲OutE本身就是Ord etype的只有我定義的,因此你必須在類型類的約束添加到實例定義爲好。

instance (Ord etype) => Eq (OutE vtype etype) where 

注意一個==/=的一個定義是足夠的類型類的工作。


注意,它往往更容易,因此認爲是更好的風格不會對data -types類型類的約束,但只是在情況/實際需要的類型類的功能的方法。

在很多情況下,人們不需要約束,只是結束了不必要的笨拙的類型簽名。

以一些有序的地圖類型Ord key => Map key value

如果我們只想列出所有密鑰,該怎麼辦?或者獲得元素的數量?我們不需要的鑰匙,是Ord這些,那麼爲什麼不見好就收地圖無限制簡單

getKeys :: Map key value -> [key] 
getLength :: Map key value -> Int 

,只是添加類型類當我們真正需要它的功能就像

insert :: Ord key => key -> value -> Map key value 
2
data (Ord etype)=> OutE vtype etype = OutE {destVertex:: vtype, edgeValue::etype} 

第一個問題:這是consdered不良作風。你的數據類型聲明不應該有約束。保留函數的約束,就像容器包一樣。

instance Eq (OutE vtype etype) where 

第二個「問題」。您可以在數據聲明後添加deriving (Eq)。我猜你知道,並且明確地寫實例自己的學習(對你有好處)...

instance Eq (OutE vtype etype) where 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

第三個問題:如果他們是Eq類的,你不能公平比較值。所以,你想說etype由方程約束:

instance (Eq etype) => Eq (OutE vtype etype) where 
    (==) = applyFunBy edgeValue (==) 
    (/=) = applyFunBy edgeValue (/=) 

第四,你實際上並不需要寫一個實例都(==)和(/ =)。一旦你定義了其中一個,默認值就可以工作。

+0

(Eq)將根據** all **記錄字段生成相等運算符(從而生成一個帶有Eq vtype的繁瑣的Eq實例),而在問題中給出的顯式實例只是根據「edgeValue」 '。 – Dario 2010-11-17 17:49:11

+0

對,我沒有注意到他寫了那麼多之後才這麼做。感謝您指出了這一點。 – 2010-11-17 19:02:38