在递归惰性数组的索引处重新定义值

时间:2014-04-18 13:58:56

标签: arrays haskell

我尝试重新定义已定义索引的值时出现<<loop>>错误。

简化示例:

ghci > let axs = array (1,5) [(1,1),(2,2),(3,3),(4,4),(5,5),(1, 1 + axs!1)]
ghci > axs
array (1,5) [(1,^CInterrupted.

这将循环。我假设Data.Array的懒惰性质是造成这种行为的原因。

另一方面,这不会循环,并将按预期工作(重新定义索引1)。

ghci > array (1,5) [(1,1),(2,2),(3,3),(4,4),(5,5),(1,6)]
array (1,5) [(1,6),(2,2),(3,3),(4,4),(5,5)]

有没有办法通过递归自我来重新定义索引值? 我假设我需要强制对所需索引进行评估,以便能够更新&#34;再次使用前一个值。 这是可能的还是我不应该/不能这样使用阵列?

1 个答案:

答案 0 :(得分:5)

在递归定义中,右边定义的东西的含义是它的最终值。所以

x = x + 1

将是一个无限循环。在数组定义中(在GHC中),索引的值是它的最后一次出现,所以

axs = array (1,5) [(1,1),(2,2),(3,3),(4,4),(5,5),(1, 1 + axs!1)]

相同
axs = array (1,5) [(2,2),(3,3),(4,4),(5,5),(1, 1 + axs!1)]

这一点的重要部分是

axs' = array (1,1) [(1, 1 + axs!1)]

的想法相同
x = 1 + x

请注意&#34;重新定义&#34;在Haskell标准中根本不允许在数组定义中,并且总是循环或抛出异常。 GHC允许它,但这并不严格是与标准的一致。

即使在GHC中,重新定义&#34;并非当务之急。您不是逐个设置数组中的值。相反,数组定义是整个数组的声明性规范。

如果您想要一种构造数组的命令式方法,请使用st monad

未经测试:

arr = runSTArray $ do
  retArr <- newArray (1,5) [(1,1),(2,2),(3,3),(4,4),(5,5)]
  curVal <- readArray retArr 1
  writeArray retArr 1 (curVal + 1)
  retArr