好吧,我正试图绕着类型类包围,所以我试图为几何向量运算定义一个类型类。我设法让它为组件明智+,-,*,/;
工作,但我正在努力使用点积。
class GeomVector a where
(>+) :: a -> a -> a
(>-) :: a -> a -> a
(>*) :: a -> a -> a
(>/) :: a -> a -> a
(>.) :: a -> a -> Double
data Vector a = Vec [a]
deriving Show
instance (Fractional a) => GeomVector (Vector a) where
(>+) (Vec u) (Vec v) = Vec $ zipWith (+) u v
(>-) (Vec u) (Vec v) = Vec $ zipWith (-) u v
(>*) (Vec u) (Vec v) = Vec $ zipWith (*) u v
(>/) (Vec u) (Vec v) = Vec $ zipWith (/) u v
(>.) (Vec u) (Vec v) = sum $ u >* v
显然我的(>。)实例定义不起作用,因为结果是Fractional a
类型,而不是Double
。
但是我不知道如何从类中的声明中获得这种行为。
我喜欢做的事情是:
class GeomVector [a] where
(>.) :: [a] -> [a] -> a
但这是无效的,因为[a]
是一种类型,而不是一种类型变量。
我希望我能更好地解释一下,但老实说我真的不明白这么做。希望代码能让我更加明显地解决我正在努力的问题。
答案 0 :(得分:5)
这是一个可行的选项:
class GeomVector v where
(>+) :: Num a=> v a -> v a -> v a
(>-) :: Num a=> v a -> v a -> v a
(>*) :: Num a=> v a -> v a -> v a
(>/) :: Fractional a=> v a -> v a -> v a
(>.) :: Num a=> v a -> v a -> a
data Vector a = Vec { vecList :: [a] }
deriving Show
instance GeomVector Vector where
(>+) (Vec u) (Vec v) = Vec $ zipWith (+) u v
(>-) (Vec u) (Vec v) = Vec $ zipWith (-) u v
(>*) (Vec u) (Vec v) = Vec $ zipWith (*) u v
(>/) (Vec u) (Vec v) = Vec $ zipWith (/) u v
(>.) u v = sum $ vecList (u >* v)
因此GeomVector
的所有实例都会像* -> *
类一样Monad
。并且这些方法的类型不会被不必要地限制为Fractional
类型,因为你在那里划分了某个地方。
您也可以考虑让您的课程尽可能小(让>.
成为课外的多态函数)以及您真正想要的是一个类型类。但这一切都取决于你的设计,我不想假设我比你知道的更好!