4

我对 Haskell 很陌生,在尝试编译Frag时遇到了这个错误。

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或类似的东西,但我不确定我到底需要做什么。

4

3 回答 3

6

class (Eq a,Floating a) => VectorSpace v a | v -> a如果你想在你的默认实现中使用/=,我猜你需要拥有。a

第二种选择是normalize从类中删除并使其成为普通函数。

第三种选择是将约束添加到 的类型normalize,使其成为Eq a => v -> v

于 2013-03-19T05:55:02.400 回答
5

在 ghc 7.4.1 之前,Num a类有Eq a约束,所以 anyNum a也有Eq a. Floating a有约束Num a,所以什么Floating a也有Eq a

但是,这在 7.4.1 中发生了变化,其中Eq a约束(以及Show a约束)已从Num类中删除。这就是代码不再工作的原因。

所以问题的解决方案正是 aleator 给出的:将Eq a约束显式添加到VectorSpace类中。

或者,您可能想要下载旧版本的 ghc(例如,基于 wiki 注释的 6.8)。该版本应该编译程序而不做任何更改。然后,如果您愿意,可以更新代码以使其与较新版本的 ghc 一起使用。

于 2013-03-19T07:24:42.330 回答
1

This isn't an answer to your question (which has already been answered), but since it's not easy to paste blocks of code into comments, I'll add it as an "answer".

You might prefer to use type families instead of functional dependencies. Type families allow you to do everything you can do with functional dependencies, plus a whole lot more. Here's one way to write your code using type families. It looks very similar to your original code, except that your type variable a has been replaced with a "call" to a type function Metric v (the best name I could think of offhand.)

{-# 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

Here are some useful links:

于 2013-03-19T11:33:32.380 回答