[英]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 -> a
类a -> 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.