Haskell 定义访问多维数组的运算符

Haskell 定义访问多维数组的运算符,haskell,multidimensional-array,Haskell,Multidimensional Array,我的想法是定义一个操作符,它接受(可能的)多维列表和索引列表,并返回元素。我的原型尝试是: (!!!) xs [i] = xs !! i (!!!) xs (cI : restI) = (xs !! cI) !!! restI 回顾过去,这显然有很多问题。我无法先算出类型签名,然后我意识到在第2行中(xs!!cI)的返回类型将不断变化,并且可能不总是列表(在最后一次“迭代”中) 我意识到,要使用标准下标运算符访问多维数组,您可以简单地将其链接如下: [[1,2,3],

我的想法是定义一个操作符,它接受(可能的)多维列表和索引列表,并返回元素。我的原型尝试是:

(!!!) xs [i]            = xs !! i
(!!!) xs (cI : restI)   = (xs !! cI) !!! restI
回顾过去,这显然有很多问题。我无法先算出类型签名,然后我意识到在第2行中(xs!!cI)的返回类型将不断变化,并且可能不总是列表(在最后一次“迭代”中)

我意识到,要使用标准下标运算符访问多维数组,您可以简单地将其链接如下:

[[1,2,3],[4,5,6],[7,8,9]] !! 1 !! 1 = 5
意识到这看起来很像褶皱,所以我试着:

(!!!) xxs inds = foldl (!!) xxs inds
or simply (!!!) = foldl (!!) 
但是我得到了和我第一次尝试相同的错误;我试图构造一个无限类型

这种类型的功能是否可能(通过黑客或其他方式)?我开始认为它的类型只是太悬而未决,无法工作

举个例子,我的目标是:

[[1,2,3],[4,5,6],[7,8,9]] !!! [1,1] = 5

只要您不一定要使用列表来存储索引,就可以不费吹灰之力地完成这项工作。索引必须作为数据类型传递,该数据类型编码类型中有多少索引。规范长度索引列表类型如下所示:

data Nat = Z | S Nat

infixr 5 :>
data Vector (n :: Nat) a where 
  Nil :: Vector Z a 
  (:>) :: a -> Vector n a -> Vector (S n) a 
那么你的功能是

(!!!) a Nil = a 
(!!!) a (i :> is) = (a !! i) !!! is 
你会注意到它没有编译。这是因为第一行和第二行中的
a
类型不同。
a
的类型必须取决于索引的类型,并且必须告诉编译器它们如何依赖它。依赖性是相当直接的;当有n个索引时,必须有n个维度的列表:

type family Dimension (n :: Nat) (v :: * -> *) (x :: *) :: * where 
  Dimension     Z v x = x 
  Dimension (S n) v x = v (Dimension n v x)
那么上面的类型就很简单了

(!!!) :: Dimension n [] a -> Vector n Int -> a

我不知道您对Haskell类型系统的更高级功能有多熟悉,但以上要求和。

您是在尝试创建一个适用于二维还是n维的函数?@Balthamos任意维。数组的深度将由给定索引列表的长度定义。与我给出的上一个示例一样,我提供了2个索引([1,1]),因此给定的数组需要是二维的。如果我给出了索引[2,1,1],列表将需要是三维的。你会想做一些类似于这个问题的事情:我想保留原始结构。这个问题更多的是出于好奇。它一开始需要一个2D下标操作符,但这很容易。这本来是可以做到的,所以我想试试看。现在问题已经清楚了,我很好奇是否有办法让它成为可能。@Carcigenicate为了优雅地解决类似Haskell类型系统中的此类问题,您确实需要依赖类型。依赖类型是那些在运行时依赖于值的类型。您希望使用n元素列表为n维列表编制索引,因此函数的类型取决于传递给它的索引列表的长度。虽然可以在Haskell中获得其中的一些特性,但它不是类型系统所支持的一流特性,需要扩展、大量样板文件和一些技巧。如果您感兴趣,请查看Agda或Idris语言。