繁体   English   中英

使用 Haskell 的 N 维数组

[英]N-dimensional Array with Haskell

在 Python 中,我们可以使用元组创建索引numpy.ndarray ,例如

cube = numpy.zeros((3,3,3,))
print(cube[(0,1,2,)])

. 然而,在 Haskell 中,要索​​引一个多层数组,这只能用多个!! 's 这似乎非常临时。

我试过foldl

foldl

  (!!)

  [[[1, 2, ....], [1, 2, ....], [1, 2, ....]],
   [[1, 2, ....], [1, 2, ....], [1, 2, ....]],
   [[1, 2, ....], [1, 2, ....], [1, 2, ....]]]

  [0, 1, 2]

然而foldl只能应用于a -> b -> aa -> b -> a函数,而不是[a] -> b -> a 其他一些信息显示hmatrix可以在 python 中执行类似numpy的操作,但它仅适用于维度不可调整的矩阵和向量。

这总是可以用 C 风格的索引来完成,即将所有数据放在一个 1d 列表中,并用乘法索引它们, 0 + 1*3 + 2*9 ,但它看起来很粗鲁,丢失了维度信息并且会导致编译器不能按正确的顺序调整它们。

如何以更抽象的方式做到这一点?

从你想要实现的问题中我不太清楚,但如果你的问题只是关于在 Haskell 中索引多维数组,那么我会尽力回答它。 感谢 @leftaroundabout 在评论部分建议massiv ,作为该库的作者,我倾向于同意他的评论。

有一件事是肯定的,出于多种原因,您不想将嵌套列表用于数组目的。 线性索引的复杂性和糟糕的性能只是其中一些原因。

构造数组

让我们看看如何使用massiv来完成它。 首先,我将翻译您的numpy示例:

cube :: Array P Ix3 Float
cube = A.replicate Seq (Sz (3 :> 3 :. 3)) 0

请注意,因为我们实际上在 Haskell 中有类型,所以我们需要对我们尝试构造的数组类型进行一些注释,例如。 装箱与未装箱、可变与不可变等。我建议通读图书馆的文档以获得有关这些主题的更多信息。 在这里,我将专注于指数,因为这就是问题所在。 为了从上述 3D 数组中的第 0 页、第 2 行和第 3 列( numpy示例中的cube[(0,1,2,)]获取元素,我们可以使用O(1)时间运算符! 在其右侧提供索引:

λ> cube ! (0 :> 1 :. 2)
0.0

请注意索引运算符! 是部分的,将导致运行时异常越界:

λ> cube ! (10 :> 1 :. 2)
*** Exception: IndexOutOfBoundsException: (10 :> 1 :. 2) is not safe for (Sz (3 :> 3 :. 3))
CallStack (from HasCallStack):
  throwEither, called at src/Data/Massiv/Core/Common.hs:807:11 in massiv-1.0.1.0-...

哪个可以通过其更安全的变体轻松避免!?

λ> cube !? (0 :> 1 :. 2) :: Maybe Float
Just 0.0
λ> cube !? (10 :> 1 :. 2) :: Maybe Float
Nothing

索引语法

numpy ,可以使用元组来索引massiv数组,但由于元组是多态的,类型检查器有时会更棘手地推断出正确的东西,而且在massiv最多支持 5 维的元组。 这就是为什么我将展示Ix n类型的示例,其中n是维数,可以是任意的。

使用平面向量时,使用常规Int进行索引(对应于Ix 1 ):

λ> let vec = makeVectorR P Seq (Sz 10) id
λ> vec
Array P Seq (Sz1 10)
  [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
λ> vec ! 7
7

对于二维,有一个特殊的运算符:. (对应于Ix 2 ):

λ> let mat = makeArrayR P Seq (Sz (2 :. 10)) $ \(i :. j) -> i + j
λ> mat
Array P Seq (Sz (2 :. 10))
  [ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
  , [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
  ]
λ> mat ! (1 :. 3)
4

任何大于 2 的维度的索引都使用:>运算符构建(对应于Ix n ):

λ> let arr3D = makeArrayR P Seq (Sz (3 :> 2 :. 1)) $ \(i :> j :. k) -> i + j + k
λ> arr3D ! (2 :> 1 :. 0)
3
λ> let arr4D = makeArrayR P Seq (Sz (4 :> 3 :> 2 :. 1)) $ \(h :> i :> j :. k) -> h + i + j + k
λ> arr4D ! (3 :> 2 :> 1 :. 0)
6

可以在自述文件的#index部分中找到有关带有示例的索引的更多信息。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM