2011-07-30 26 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的实例。所以你可以使用<+>|+|什么的。