我一直在搞乱一个简单的张量库,我在其中定义了以下类型。
$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
函数的其他方法吗?
答案 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
。