2013-03-19 54 views
4

對於Haskell,我很新,在編譯Frag時遇到了這個bug。無法推斷(Eq a),將Eq添加到類型

src/AFRPVectorSpace.hs:51:25: 
    Could not deduce (Eq a) arising from a use of `/=' 
    from the context (VectorSpace v a) 
     bound by the class declaration for `VectorSpace' 
     at src/AFRPVectorSpace.hs:(32,1)-(53,23) 
    Possible fix: 
     add (Eq a) to the context of 
     the class declaration for `VectorSpace' 
    In the expression: nv /= 0 
    In the expression: 
     if nv /= 0 then v ^/ nv else error "normalize: zero vector" 
    In an equation for `normalize': 
     normalize v 
      = if nv /= 0 then v ^/ nv else error "normalize: zero vector" 
      where 
       nv = norm v 

培訓相關代碼:

class Floating a => VectorSpace v a | v -> a where 
    zeroVector :: v 
    (*^)   :: a -> v -> v 
    (^/)   :: v -> a -> v 
    negateVector :: v -> v 
    (^+^)  :: v -> v -> v 
    (^-^)  :: v -> v -> v 
    dot   :: v -> v -> a 
    norm  :: v -> a 
    normalize :: v -> v 

    v ^/ a = (1/a) *^ v 

    negateVector v = (-1) *^ v 

    v1 ^-^ _ = v1 ^+^ v1 -- (negateVector v2) 

    norm v = sqrt (v `dot` v) 

    normalize v = if nv /= 0 then v ^/ nv else error "normalize: zero vector" 
     where 
     nv = norm v 

我的第一個猜測是,我需要添加一個Deriving Eq什麼之類的,但我不知道究竟我需要做的。

+0

我要說,你真的不想要一個'Eq'約束對於浮動類型,通常有點麻煩。我寧願添加'class(Num f)=> TestZero f其中{isZero :: f-> Bool}',然後'instance(Eq f,Num f)=> instance TestZero f where {isZero =(== 0)}'。 – leftaroundabout 2013-03-19 10:49:37

+0

沒有必要將'0'轉換爲矢量類型'v'。然而,如果'nv/= 0 then'改爲'if vv/= 0 then'就應該這樣做,因爲'a'是一個數字類型。 – luqui 2013-03-20 13:22:58

回答

6

如果你想在你的默認實現中使用/=a,我想你應該有class (Eq a,Floating a) => VectorSpace v a | v -> a

第二種選擇是從類中刪除normalize,並將其設置爲普通函數。

第三種替代方法是將約束添加到normalize的類型,使其成爲Eq a => v -> v

+0

只有'normalize'需要被移除 – huon 2013-03-19 07:30:56

+0

如果你想在類中保持'normalize',你可以改變它的類型簽名爲'normalize :: Eq a => v - > v'。 – mhwombat 2013-03-19 11:05:26

+0

編輯,以包括評論.. – aleator 2013-03-19 13:55:07

5

在ghc 7.4.1之前,Num a類有Eq a約束,所以任何Num a也有Eq aFloating a有一個約束Num a,因此任何Floating a也是Eq a

但是,這改變了7.4.1,其中Eq a約束(以及Show a約束)從Num類中刪除。這就是代碼不再工作的原因。

所以問題的解決方案正是阿萊託給出的:將Eq a約束明確地添加到VectorSpace類。

或者,您可能想要下載舊版本的ghc(例如基於wiki註釋的6.8)。該版本應該不做任何改變地編譯程序。然後,如果你願意,你可以更新代碼以使其與更新版本的ghc一起工作。

1

這不是您的問題的答案(已經回答),但由於將代碼塊粘貼到評論中並不容易,所以我將其添加爲「答案」。

您可能更喜歡使用類型族而不是函數依賴項。類型族允許你做所有你可以做的功能依賴,再加上更多。以下是使用類型族編寫代碼的一種方法。它看起來非常類似於您的原始代碼,不同之處在於您的類型變量a已被替換爲「調用」類型函數Metric v(我能想到的最好的名字。)

{-# LANGUAGE TypeFamilies, FlexibleContexts #-} 

class Floating (Metric v) => VectorSpace v where 
    type Metric v 
    zeroVector :: v 
    (*^)   :: Metric v -> v -> v 
    (^/)   :: v -> Metric v -> v 
    negateVector :: v -> v 
    (^+^)  :: v -> v -> v 
    (^-^)  :: v -> v -> v 
    dot   :: v -> v -> Metric v 
    norm  :: v -> Metric v 
    normalize :: Eq (Metric v) => v -> v 

    v ^/ a = (1/a) *^ v 

    negateVector v = (-1) *^ v 

    v1 ^-^ _ = v1 ^+^ v1 -- (negateVector v2) 

    norm v = sqrt (v `dot` v) 

    normalize v = if nv /= 0 then v ^/ nv else error "normalize: zero vector" 
     where 
     nv = norm v 

下面是一些有用的鏈接:

+0

我會調用相關的類型'標量'(或'ScalarOf'),我認爲這是數學上更常用的方式來說'該領域這個向量空間已經結束'。感謝haskell-cafe鏈接,它回答了一個關於來回TF的問題! – yatima2975 2013-03-19 12:52:10