不可扣除的关系

时间:2015-02-10 23:03:28

标签: haskell typeclass

为什么ab之间的关系无法推断?

class Vector a where
    (<.>) :: Num b => a -> a -> b

data Vec2 a
    = Vec2 (a, a)

    deriving Show

instance Num a => Vector (Vec2 a) where
    Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d

我希望有一个Vec2代数数据结构,其中组件可以是任何数字。

2 个答案:

答案 0 :(得分:7)

(<.>) :: Num b => a -> a -> b

以上意味着(<.>)能够生成该函数可能需要的调用者任何类型的数字。

例如,如果x,yVec2 Double,则可以调用x <.> y返回Integer。编译器然后抱怨它在发布的实例中的实现不够通用,因为它返回Double而不是调用者可能选择的任何类型。

我认为这不是该代码的目的。

您可能希望切换到多参数类(您需要启用一些扩展,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

答案 1 :(得分:2)

正如@ chi的回答所说,你的代码并不能使b依赖a。为了得到我想你想要的东西,你可以使用一个相关的类型族:

{-# LANGUAGE TypeFamilies #-}

class Vector a where
    type Element a
    (<.>) :: a -> a -> Element a

data Vec2 a
    = Vec2 (a, a)

    deriving Show

instance Num a => Vector (Vec2 a) where
    type Element (Vec2 a) = a
    Vec2 (a, b) <.> Vec2 (c, d) = a * c + b * d

另一种选择是使用具有功能依赖性的多参数类型类,但我认为这里更复杂。