通过固定参数来简化类型

时间:2017-02-02 14:18:49

标签: haskell

这是对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 

2 个答案:

答案 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.17Matrix上的模式匹配看起来没用,因为它不绑定任何变量;但它确实绑定了Elem约束,该约束在unsafeCoeff的调用中使用。

答案 1 :(得分:0)

编译器并不总是建议正确的提示,但在这种情况下,当它表示没有实例(Elem a(CType a))时,它确实意味着。你给它约束了Elem a b,其中b由函数的第一个参数决定。但是,你必须调用需要b~CType a的东西。这是编译器无法弄清楚的。您需要将函数的类型限制为Matrix a(CType a) - >一些 - >其他 - >参数 - >结果,并将约束Elem a b更改为Elem a(CType a)。 为这些定义同义词可能很方便: 类型CMatrix a =矩阵a(CType a) 类型CElem =(Elem a(CType a)) - 需要-XConstraintSynonyms 如果你总是打算使用b~CType a,那么更好的选择可能是删除对Elem的功能依赖。即使你不想总是b~CType,你仍然可以删除功能依赖,并使CType成为Elem的关联类型: class(Num a,Cast a(ElemType a),Cast(ElemType a)a,Storable(ElemType a),Code(ElemType a))=> Elem在哪里   键入ElemType a   ...