为张量类型定义Functor实例(Idris)

时间:2016-05-21 20:50:41

标签: idris

我最近一直在学习Idris,并决定尝试编写一个简单的张量库。我从定义类型开始。

data Tensor : Vect n Nat -> Type -> Type
  Scalar : a -> Tensor [] a
  Dimension : Vect n (Tensor d a) -> Tensor (n::d) a

如您所见,Tensor类型由描述张量维度的Vect Nat参数化,以及描述其内容的类型。到现在为止还挺好。接下来,我决定尝试将Tensor类型设为Functor

instance Functor (Tensor d) where
  map f (Scalar x)    = f x
  map f (Dimension x) = map f x

伊德里斯给了我以下错误。

Unifying `b` and `Tensor [] b` would lead to infinite type

好。从错误中,我认为问题可能是map的第一种模式过于具体(即,只有当地图的类型声明接受任何张量时才会接受标量)。这看起来很奇怪,但我想我会尝试用with语句重写它。

dimensions : {d : Vect n Nat} -> Tensor d a -> Vect n Nat
dimensions {d} _ = d

instance Functor (Tensor d) where
  map f t with (dimensions t)
    map f (Scalar x)    | []     = f x
    map f (Dimension x) | (_::_) = map f x

但我得到了同样的错误。我在Haskell方面有相当多的经验,但是我仍然不习惯在依赖类型编程中使用的术语,尤其是Idris,所以任何理解错误信息的帮助都会非常感激。

1 个答案:

答案 0 :(得分:3)

(注意:从Idris 0.10开始,instance关键字已弃用,应简单地省略。

任务是将函数应用于Scalar构造函数中的所有元素,否则保持结构不变。因此,我们需要将Scalar映射到ScalarDimensionDimension,并且由于Dimension包含递归出现的向量,我们应该使用{{1 }} Vect可以访问它们。

map

因此,在Functor (Tensor d) where map f (Scalar x) = Scalar (f x) map f (Dimension xs) = Dimension (map (map f) xs) 中,第一个map (map f) xs用于映射mapVect是递归调用。