2011-07-30 56 views
4

請看下面的例子:Haskell - 添加typeclass?

data Dot = Dot Double Double 
data Vector = Vector Double Double 

首先,我想超載+運營商Vector加法。如果我想超載平等(==)運算符,我會寫什麼樣子:

instance Eq Vector where ...blahblahblah 

但我找不到,如果有Add類型類使Vector的行爲就像相加操作的類型。我甚至找不到Haskell類型類的完整列表,我知道只有少數來自不同的教程。這樣的清單是否存在?

另外,我可以重載+運營商將Vector添加到Dot(它似乎相當邏輯,不是嗎?)。

+1

爲什麼你需要區分點和矢量?正如其他人所提到的,(+)在Num類型類中,但不能用點和向量實現(+),因爲兩個參數必須是相同的類型。如果您可以將這兩種類型視爲可互換,那麼您可以只有一種類型,並將該類型作爲Num的一個實例。 – Boris

+1

儘管您可能正在尋找'Num',那麼'Monoid'類型也可能會對您感興趣。請參閱其他資源[LYAH#monoids](http://learnyouahaskell.com/functors-applicative-functors-and-monoids#monoids) –

回答

7

Prelude中的operator +由類型類Num定義。然而顧名思義,這不僅定義了加法,而且還定義了許多其他數字操作(特別是其他算術運算符以及使用數字文字的能力),因此這不符合您的用例。

除非你想隱藏Prelude的+運算符(這意味着如果你仍然希望能夠爲Integer,Double等創建你自己的Addable實例,那麼沒有辦法爲你的類型重載+在數字上使用+)。

+3

我會爭辯說,如果您實施Num並將所有(+)未定義。在實踐中,Haskell程序員有時會實現類型類,並留下一些他們不會使用的方法undefined。 –

5

您可以編寫一個instance Num Vector以重載+以增加向量(以及其他有意義的運算符)。

instance Num Vector where 
    (Vector x1 y1) + (Vector x2 y2) = Vector (x1 + x2) (y1 + y2) 
    -- and so on 

但是,請注意+有型Num a => a -> a -> a,即兩個操作數和結果都必須是同一類型。這意味着你不能有Dot加上VectorDot

雖然你可以隱藏PreludeNum並指定自己的+,這很容易造成混亂,使其難以與常規的算術一起使用你的代碼。

我建議你定義自己的運營商向量點此外,例如

(Dot x y) `offsetBy` (Vector dx dy) = Dot (x + dx) (y + dy) 

或使用符號,如果你喜歡的東西更短一些變種。

+0

隱藏'(+)'或全部'Num',並使用您自己的代替,沒有任何*錯誤*。問題是,除非是非常醜陋的黑客,否則基本上最終會被迫完全替換大部分Prelude的數字類。 –

13

一個簡單的方法來發現哪些類型類信息(如果有的話)的功能屬於是使用GHCI:

Prelude> :i (+) 
class (Eq a, Show a) => Num a where 
    (+) :: a -> a -> a 
    ... 
     -- Defined in GHC.Num 
infixl 6 + 
4

我有時會看到人們定義自己的運營商那種看起來像從前奏的人。即使++可能也會使用該符號,因爲他們想要傳達「將」兩個列表「添加」在一起的想法,但它沒有意義,因爲列表是Num的實例。所以你可以使用<+>|+|什麼的。