Haskell类型类型约束和演绎

时间:2013-08-17 03:20:44

标签: haskell typeclass

我一直在阅读“了解你一个Haskell”这本书,我正试图围绕Haskell Type Classes。作为练习,我正在尝试创建一个简单的矢量类型类。以下代码片段给了我一些悲伤(导致我第一篇发布到StackOverflow):

data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)

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

instance (Num a) => Vector (Vec2 a) where
    Vec2 (x,y) <* a = Vec2 (a*x, a*y)

我收到以下错误消息:

Could not deduce (a~b) from the context (Num a) or from (Num b) bound by the type signature for
    <* :: Num b => Vec2 a -> b -> Vec2 a

似乎在类型类中指定的Num应提供a的类型,并且实例中的Num a注释应提供x的类型和{ {1}},为什么抱怨?我对这段代码有什么误解?

3 个答案:

答案 0 :(得分:7)

(*) :: Num a => a -> a -> a的类型。但是,当您实际尝试使用*时,实际上是将两个不相关的类型与Num个实例相乘,并且编译器无法推断它们是相同的。

要更清楚地解释一下<*的类型和b的普遍量化

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

你在这里说的是,给我任何具有Num实例的类型,我将能够将其与我的向量相乘,但你想说的是不同的东西。

您需要了解类型a中的Vec2 ab类型中的(<*) :: Num b => a -> b -> a相同的情况,然后才能将它们相乘。这是一个使用typefamilies来确保这种约束的解决方案。

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}

data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)

class (Num (VectorOf a)) => Vector a where
    type VectorOf a :: *
    (<*) :: a -> (VectorOf a) -> a

instance (Num a) => Vector (Vec2 a) where
    type VectorOf (Vec2 a) = a
    Vec2 (x,y) <* a = Vec2 (a*x, a*y)

答案 1 :(得分:0)

编译器无法验证所涉及的Num个实例是否实际上是同一类型。确实,它们都是Num个实例,但还需要的是它们必须是相同的实例。

否则,你可以这样写:

Vec2 (1 :: Double, 2 :: Double) <* (3 :: Int)

当时间到来时不会飞,例如:(1 :: Double) * (3 :: Int)

答案 2 :(得分:0)

我认为问题是(*)类型(Num a) => a -> a -> a而非(Num a, Num b) => a -> b -> a编译器预期。

我不熟悉Haskell的数字转换,但我的解决方法有限,因为第二个参数是Integral的实例。

data Vec2 a = Vec2 (a,a) deriving (Show, Eq, Read)    

class Vector a where
    (<*) :: (Integral b) => a -> b -> a

instance (Num a) => Vector (Vec2 a) where
    Vec2 (x,y) <* a = Vec2 (x*b, y*b)
        where b = fromIntegral a

因为fromIntegral的类型为(Integral a, Num b) => a -> b,所以可以根据需要转换*的第二个参数。