我上课
import Linear
class Coordinate c where
rotate :: Num a => Quaternion a -> c a -> c a
translate :: Num a => V3 a -> c a -> c a
,我已经为其定义了实例
instance Coordinate V3 where
rotate _ = id
translate p = (p+)
instance Coordinate Quaternion where
rotate o = (o*)
translate _ = id
现在,我想为该类的一对成员定义一个实例。
instance (Coordinate a, Coordinate b) => Coordinate (a, b) where
rotate o (a, b) = (rotate o a, rotate o b)
translate p (a, b) = (translate p a, translate p b)
问题在于,这不起作用,因为编译器需要a
和b
的参数。但是添加类似
instance (Coordinate a, Coordinate b, Num c) => Coordinate (a c, b c) where
move p (a, b) = (move p a, move p b)
translate p (a, b) = (translate p a, translate p b)
也不起作用,因为这会导致表达式的类型为*
而不是* -> *
。我可以看到以上两种情况都不正确,但是我不确定如何解决。我想应该有某种形式的约束来使Num
和a
的{{1}}类型保持相同,但是我不知道从语法上看起来会是什么样。
答案 0 :(得分:7)
您不能为内置对类型创建此Coordinate
类的实例。您需要更改其中之一。
可以将Coordinate
类更改为以普通的Type
作为参数:
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
import Data.Kind (Type)
class Num (Component c) => Coordinate c where
type Component c :: Type -- every Coordinate type has a Component type
rotate :: Quaternion (Component c) -> c -> c
translate :: V3 (Component c) -> c -> c
例如V3
实例现在看起来像
instance Num a => Coordinate (V3 a) where
type Component (V3 a) = a
rotate _ = id
translate = (+)
该对实例将使用等式约束,这就是您要寻找的东西
instance (Coordinate a, Coordinate b, Component a ~ Component b) => Coordinate (a, b) where
type Component (a, b) = Component a -- or = Component b
rotate p (l, r) = (rotate p l, rotate p r)
translate p (l, r) = (translate p l, translate p r)
使用Product
代替配对:
import Data.Functor.Product
instance (Coordinate a, Coordinate b) => Coordinate (Product a b) where
rotate p (Pair l r) = Pair (rotate p l) (rotate p r)
translate p (Pair l r) = Pair (translate p l) (translate p r)