在 Haskell 中生成二维网格

10

我正在学习Haskell,并希望编写一个类似于C语言中生成二维网格的函数:

int data[3][3]

什么是一个可接受且优雅的方法?Zip?Foldl?

我可以像这样声明一个:

x = [[0,0,0],
     [0,0,0],
     [0,0,0]]

但我想要一个带有x和y参数的函数。很难理解不使用for/while循环的最简单方法 :(


1
“generate” 是什么意思? - vicvicvic
1
@Cyclone:在Haskell中,for/while循环长什么样? - Gabe
@Gabe: 我想象中的东西类似于 http://www.xoltar.org/old_site/2003//sep/09/haskellLoops.html - Cyclone
1
即便如此,您仍然面临大多数Haskell数据结构(例如Data.Array)是不可变的问题。这意味着您无法逐个初始化数组。 - Thomas M. DuBuisson
3个回答

19

您似乎在问“在Haskell中,我应该使用什么代替数组”,对吗?您询问了使用列表的情况,但这显然不是数组,并且对于需要非顺序访问的任何严肃工作都应该避免使用它们(例如,列表提供O(n)元素访问而不是O(1))。

您应该考虑的软件包:array(旧的、标准的Haskell数组)、vector(新的、使用流融合技术、快速、合理的API、封装或非封装、但只有一个维度,除非您将它们嵌套),以及repa(仅适用于较新的GHC版本,但允许多维数组和并行操作,即使使用非封装表示)。

初始化它们中的任何一个最简单的方法是它们各自的“fromList”函数。例如:

import Data.Vector as V
...
    V.fromList $ map V.fromList [[01,02,03],[11,12,13],[22,22,23]]

1
公正的观点,TomMD!我有点反对“严肃工作”的说法 - 在我看来,“性能关键”是更好的描述。 - vicvicvic
1
vicvicvic:没错,我刚刚编辑了那部分内容,更好地强调我指的是性能关键的非顺序访问。 - Thomas M. DuBuisson

3
如果你想要一个不太复杂、读取快速并且有合理的“更新”速度,那么你应该考虑使用带有 (x,y) 对作为键的 Mapimport Data.Map)。添加辅助函数进行范围检查和返回缺失条目的默认值,这样就可以很好地替代矩阵了(只要矩阵不是特别大)。

3

我会使用一个列表的列表(:: [[a]]),可能会加入一些新类型,以确保所有列表的长度相等。

要创建包含 n 个值的列表,您可以使用 replicate :: Int -> a -> [a],所以要生成一个列表的列表,您只需要再次复制该列表...

grid :: Int -> Int -> a -> [[a]]
grid x y = replicate y . replicate x

在这里,a参数允许您生成任何类型的“零”值列表。可以像这样使用:

> grid 3 3 0
[[0,0,0],[0,0,0],[0,0,0]]
> grid 2 3 False
[[False,False],[False,False],[False,False]]

编辑:此坐标系使用(y,x),我意识到我在考虑(行,列)。您可以只需交换grid中的x和y以获取“通常”的系统。


列表是数组的一个非常差的替代品。除非您确定不会有任何性能问题,否则Dominic,我建议考虑具有O(1)访问的不同数据结构。 - Thomas M. DuBuisson
哇,这很优雅。谢谢。现在要理解复制! - Dominic Bou-Samra
@TomdMD。嗯,虽然性能不是关键,但我宁愿不使用朴素的解决方案,而是使用更好的解决方案。会研究一下Data.Vector。 - Dominic Bou-Samra
@Dominic:replicate实际上非常简单。你只需要给它一个n和一个元素,它就会给你一个长度为n且填充了该元素的列表(例如,replicate 3 0 = [0,0,0])。 - vicvicvic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接