这是对this question的跟进,但问题在应用和原因上略有不同,所以我选择提出一个新问题。
考虑这些定义(编辑:这些是外部库的一部分):
class (Num a, Cast a b, Cast b a, Storable b, Code b) => Elem a b | a -> b where
data Matrix a b where
Matrix :: Elem a b => !Int -> !Int -> !(Vector b) -> Matrix a b
instance Elem Float CFloat where
instance Elem Double CDouble where
instance Elem (Complex Float) (CComplex CFloat) where
instance Elem (Complex Double) (CComplex CDouble) where
换句话说,浮点矩阵的底层C类型由函数依赖性Elem“固定”。
现在为了实现某些容器特定类的某些实例(在Lookup类的特定情况下,但是镜头中的Ixed可能是另一个候选者)我需要一个带有一个类型参数的Matrix类型。
我尝试了以下内容:
type family CType a where
CType Double = CDouble
CType Float = CFloat
CType (Complex Double) = (CComplex CDouble)
CType (Complex Float) = (CComplex CFloat)
newtype MatX a = MatX { getMatX :: Matrix a (CType a) }
请注意,我不允许在newtype声明中省略“b”类型,因此类型同义词可用作修复内部类型的方法。
但是,Matrix类型上的所有函数都具有类似
的类型(Elem a b) => Matrix a b -> some -> other -> params -> result
作为示例,unsafeCoeff函数如下所示:
unsafeCoeff :: Elem a b => Int -> Int -> Matrix a b -> a
unsafeCoeff row col (Matrix rows _ vals) = cast $ Data.Vector.Storable.unsafeIndex vals $ col * rows + row
使用这种类型MatX,例如:
instance Lookup MatX where
lookup (i,j) m = Just $ unsafeCoeff i j (getMatX m)
给我错误“没有实例(Elem a(CType a))”。由于我不允许指定这些实例(因为在实例声明中不允许使用类型同义词),所以我在这一点上陷入困境。我明白为什么编译器不能假设确实给出了Elem a(CType a),但我不知道如何指定这种关系。
加成:
我也尝试过这样做:
instance Lookup (Matrix a) where
lookup (i,j) m = Just $ unsafeCoeff i j m :: Maybe a
但是“b”是容器的元素类型,查找函数必须返回(未指定)b。
编辑:为了完整起见,从上面的链接中定义了Lookup:
type family Key f
class Lookup f where
lookup :: Key f -> f a -> Maybe a
答案 0 :(得分:2)
你应该可以写
type instance Key MatX = (Int, Int)
instance Lookup MatX where
lookup (i,j) (MatX m@(Matrix {})) = Just $ unsafeCoeff i j m
Matrix
构造函数上的模式匹配将其包含的Elem a b
约束带入范围。 (eigen
库让你这样做很奇怪,因为它必须在Matrix
构造函数上匹配。)
编辑添加更多解释。上面lookup
的定义是一种较短的写作方式
lookup (i,j) (MatX m) = case m of
Matrix _ _ _ -> Just $ unsafeCoeff i j m
对于模式匹配,请参阅Haskell报告的section 3.17。 Matrix
上的模式匹配看起来没用,因为它不绑定任何变量;但它确实绑定了Elem
约束,该约束在unsafeCoeff
的调用中使用。
答案 1 :(得分:0)