[英]Haskell Typeclass Type Constraints and Deduction
我一直在阅读“Learn You a 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
实例中应该提供的类型spefication x
和y
,那么为什么抱怨? 我对这段代码有什么误解?
(*) :: Num a => a -> a -> a
。 但是,当您实际尝试使用*
,实际上您将两个具有Num
实例的不相关类型相乘,并且编译器无法推断它们是相同的。
为了更清楚地解释它,请看<*
的类型和b
的通用量化
(<*) :: (Num b) => a -> b -> a
你在这里说的是,给我任何类型的Num
实例,我将能够将它与我的向量相乘,但你想说的是不同的东西。
你需要知道a
类型Vec2 a
中的b
与类型(<*) :: 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)
编译器无法验证所涉及的两个Num
实例实际上是否为同一类型。 当然,它们都是Num
实例,但是还需要它们必须是同一个实例。
否则,你可以写这样的东西:
Vec2 (1 :: Double, 2 :: Double) <* (3 :: Int)
什么时候不能飞,ex: (1 :: Double) * (3 :: Int)
。
我认为问题是(*)
的类型(Num a) => a -> a -> a
而不是(Num a, Num b) => a -> b -> a
complier expect。
我不熟悉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
,它可以根据需要转换*
的第二个参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.