用于张量索引的Idris非平凡类型计算

时间:2016-05-23 23:47:03

标签: dependent-type idris

我一直在搞乱一个简单的张量库,我在其中定义了以下类型。

$cartItems = Session::get('cartItems');
$newItems = [];    

foreach ($cartItems as $cartItem) {
        if ($cartItem['product']->id == $product_id && $cartItem['size'] == $request['size']) {
                $cartItem['quantity'] += (int)$request['quantity'];
        } else {
                $newItems[] = [
                        'product' => $product,
                        'size' => $request['size'],
                        'quantity' => $request['quantity']
                ];
        }
}

Session::put('cartItems', $cartItems + $newItems);

该类型的矢量参数描述了张量"尺寸"或"形状"。我目前正在尝试定义一个函数来安全地索引到data Tensor : Vect n Nat -> Type -> Type where Scalar : a -> Tensor [] a Dimension : Vect n (Tensor d a) -> Tensor (n :: d) a 。我曾计划使用Tensor来做这件事,但我遇到了一个问题。因为Fin的顺序是未知的,所以我可能需要任意数量的索引,每个索引都需要不同的上限。这意味着Tensor个索引不足,因为每个索引都有不同的类型。那驱使我看看使用元组(称为"对和#34;在Idris中?)。我编写了以下函数来计算必要的类型。

Vect

此功能按预期工作,从维度向量计算适当的索引类型。

TensorIndex : Vect n Nat -> Type
TensorIndex []      = ()
TensorIndex (d::[]) = Fin d
TensorIndex (d::ds) = (Fin d, TensorIndex ds)

但是当我尝试定义实际的> TensorIndex [4,4,3] -- (Fin 4, Fin 4, Fin 3) > TensorIndex [2] -- Fin 2 > TensorIndex [] -- () 函数...

index

... Idris在第二种情况下引发了以下错误(奇怪的是,第一种情况似乎完全没问题。)

index : {d : Vect n Nat} -> TensorIndex d -> Tensor d a -> a
index () (Scalar x) = x
index (a,as) (Dimension xs) = index as $ index a xs
index a (Dimension xs) with (index a xs) | Tensor x = x

这个错误似乎意味着,不是将Type mismatch between (A, B) (Type of (a,as)) and TensorIndex (n :: d) (Expected type) 视为极其复杂的类型同义词,而是像我希望的那样对其进行评估,而是将其视为使用TensorIndex声明定义; a"黑盒类型"可以这么说。伊德里斯在哪里划线?有没有办法让我重写data以便它按照我想要的方式工作?如果没有,你能想到写TensorIndex函数的其他方法吗?

2 个答案:

答案 0 :(得分:8)

如果您通过对维度列表进行归纳来定义Tensor,而Index被定义为数据类型,那么您的定义会更清晰。

实际上,目前您被迫对类型Vect n Nat的隐式参数进行模式匹配,以查看索引的形状。但是如果索引被直接定义为一个数据,那么约束它索引的结构的形状,一切都到位:正确的信息在typechecker的正确时间到达快乐。

module Tensor

import Data.Fin
import Data.Vect

tensor : Vect n Nat -> Type -> Type
tensor []        a = a
tensor (m :: ms) a = Vect m (tensor ms a)

data Index : Vect n Nat -> Type where
  Here : Index []
  At   : Fin m -> Index ms -> Index (m :: ms)

index : Index ms -> tensor ms a -> a
index Here     a = a
index (At k i) v = index i $ index k v

答案 1 :(得分:4)

如果您允许在()中跟踪TensorIndex,那么您的生活会变得如此简单,从那以后就可以了

TensorIndex : Vect n Nat -> Type
TensorIndex []      = ()
TensorIndex (d::ds) = (Fin d, TensorIndex ds)

index : {ds : Vect n Nat} -> TensorIndex ds -> Tensor ds a -> a
index {ds = []} () (Scalar x) = x
index {ds = _ :: ds} (i, is) (Dimension xs) = index is (index i xs)

如果您想保留TensorIndex的定义,则需要为ds = [_]ds = _::_::_设置单独的案例以匹配TensorIndex的结构:

TensorIndex : Vect n Nat -> Type
TensorIndex []      = ()
TensorIndex (d::[]) = Fin d
TensorIndex (d::ds) = (Fin d, TensorIndex ds)

index : {ds : Vect n Nat} -> TensorIndex ds -> Tensor ds a -> a
index {ds = []} () (Scalar x) = x
index {ds = _ :: []} i (Dimension xs) with (index i xs) | (Scalar x) = x
index {ds = _ :: _ :: _} (i, is) (Dimension xs) = index is (index i xs)

这是有效的,而你的原因不是因为在这里,index的每个案例都与一个TensorIndex案件完全对应,因此可以减少TensorIndex ds