【问题标题】:Defining an operator to access a multi-dimensional array定义一个操作符来访问一个多维数组
【发布时间】:2014-10-24 15:28:39
【问题描述】:

我想到了定义一个运算符,该运算符采用(可能)多维列表和索引列表,并返回元素。我的原型尝试是:

(!!!) 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

【问题讨论】:

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

标签: haskell multidimensional-array


【解决方案1】:

只要您不必使用列表来存储索引,您就可以毫不费力地做到这一点。索引必须作为数据类型传递,该数据类型对类型中有多少索引进行编码。规范长度索引列表类型如下所示:

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 类型系统更高级的特性有多熟悉,但以上需要type familiesdata kinds

【讨论】:

    猜你喜欢
    • 2019-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 2014-06-16
    • 2021-12-30
    • 2021-04-19
    相关资源
    最近更新 更多