作为练习,我尝试创建一个Vector
类型类作为练习:
class Vector v where
vplus :: v -> v -> v
vnegate :: v -> v
type V3 a = (a,a,a)
instance (Num a) => Vector (V3 a) where
(a,b,c) `vplus` (d,e,f) = (a+d, b+e, c+f)
vnegate (a,b,c) = ((-a), (-b), (-c))
我想在类型类上添加dot
函数。在上面的V3
示例中,我按如下方式实现它:
dot :: (Num a) => V3 a -> V3 a -> a
(a,b,c) `dot` (d,e,f) = a*d + b*e + c*f
但是,我似乎无法访问a
中的类型参数Vector
,因此我无法dot
对{{1}进行操作我想要的方式。我如何访问Vector
类型参数?
答案 0 :(得分:1)
您希望使用TypeFamilies
来创建关联类型:
{-# LANGUAGE TypeFamilies, TypeSynonymInstances, FlexibleInstances #-}
class Vector v where
-- Declares a family of types called Item, parametrized on the
-- instance v of Vector, and the kind of Item v must be *,
-- meaning that it must be a type, not a type constructor
-- (e.g. Maybe Int :: * vs Maybe :: * -> *)
type family Item v :: *
dot :: v -> v -> Item v
...
instance (Num a) => Vector (V3 a) where
type Item (V3 a) = a
dot (a, b, c) (d, e, f) = a*d + b*e + c*f
...
然后你可以做
> dot (1, 2, 3) ((4, 5, 6) :: V3 Int)
32
虽然我建议不要使用类型同义词实例,但最好还是使用数据类型:
data V3 a = V3 a a a deriving (Eq, Show)
instance Functor V3 where
fmap f (V3 a b c) = V3 (f a) (f b) (f c)
instance (Num a) => Vector (V3 a) where
type Item (V3 a) = a
(V3 a b c) `vplus` (V3 d e f) = V3 (a + d) (b + e) (c + f)
vnegate v = fmap negate v
dot (V3 a b c) (V3 d e f) = a*d + b*e + c*f
这有助于类型检查器,特别是它意味着您不需要上面的显式类型签名。这也意味着您的推断类型不会(a, a, a)
而是V3 a
(就像您看到[Char]
而非String
时),这更容易理解。它并不重要,但很有帮助。
如果您想知道,GHC.Exts.IsList
(与新的OverloadedLists
扩展程序一起使用)是这样的:
class IsList l where
type family GHC.Exts.Item l :: *
fromList :: [GHC.Exts.Item l] -> l
fromListN :: Int -> [GHC.Exts.Item l] -> l
toList :: l -> [GHC.Exts.Item l]