(<.>) :: Num b => a -> a -> b
Вышесказанное означает, что (<.>)
способен производить любой тип номера Вызывающий этой функции, возможно, захотите.
Например, если x,y
являются Vec2 Double
, то x <.> y
можно вызвать для возврата Integer
. Затем компилятор жалуется, что его реализация в размещенном экземпляре не является достаточно общей, поскольку она возвращает Double
s вместо любой тип, который может выбрать вызывающий.
Я думаю, что это не то, что этот код предназначен для моделирования.
Вы можете перейти к классу многопараметрической (вам необходимо включить несколько расширений, GHC покажет вам, какие из них):
class Vector a b where
(<.>) :: a -> a -> b
instance Num a => Vector (Vec2 a) a where
Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d
Поскольку теперь компилятор не может определить тип x <.> y
от типа x,y
, вы можете добавить функциональную зависимость с помощью
class Vector a b | a -> b where
(<.>) :: a -> a -> b
или в качестве альтернативы использовать семейный тип
class Vector a where
type Scalar a
(<.>) :: a -> a -> Scalar a
instance Num a => Vector (Vec2 a) where
type Scalar (Vec a) = a
Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d
[Здесь] (http://hackage.haskell.org/package/vector-space-0.8.7/docs/Data-VectorSpace.html) - стандартная реализация класса векторного пространства. Как вы увидите, он использует «Scalar» в качестве семейства ассоциированных типов, как предполагал Эржан. (Класс с '<.>' фактически является подклассом ['InnerSpace'] (http://hackage.haskell.org/package/vector-space-0.8.7/docs/Data-VectorSpace.html#t:InnerSpace) : не все векторные пространства допускают скалярное/скалярное произведение, что все они позволяют только умножать векторы со скалярами ('* ^') и вместе добавлять векторы ('^ + ^' из 'AdditiveGroup'). – leftaroundabout