Haskell:修改数组特定索引处的值

时间:2019-05-27 20:23:28

标签: haskell functional-programming

Haskell的新手。我已经创建了一个char数组,并试图找出在给定特定索引的情况下修改该数组中数据的最佳方法。

我已经创建了一个数组,该数组将在我的主方法中传递给以下方法。那部分工作正常。我只是无法弄清楚如何处理每个索引处的数据。在这种特殊情况下,如果满足以下条件,则我试图覆盖该值。我想将其返回到主菜单,以便我可以打印出更新后的电路板。

try {
...
} catch {
    case _ : Throwable => ... // catch all exceptions
}

2 个答案:

答案 0 :(得分:4)

您实际上不需要修改数组。只需让您的函数创建一个具有所需更改的新数组,就像这样:

modifyArray :: Array Int Char -> Int -> Array Int Char
modifyArray arr i =
    if i > 0 then
        if i `mod` 102 == 1 then
            arr // [(i, ' ')]
        else modifyArray arr (i-1)
    else arr   

Data.Array包含//运算符,这意味着“取左边的数组,右边应用更改,然后返回结果”。另外,由于此功能不执行任何IO,因此无需在类型签名中使用“ do”或包含IO。

答案 1 :(得分:2)

如果您打算仅更新阵列几次,则可以使用(//) :: Ix i => Array i e -> [(i, e)] -> Array i e operator,就像@JosephSible所说。

但是,如the question "How fast is Data.Array?"中所述,如果要频繁更新数组 ,这不是很有效:

  

请注意,//可能是 O(n),因为它必须遍历列表(就像命令式程序一样)。如果您需要大量的突变,则可以使用MArray MVector

因此,这意味着对于大型数组,更新数组可能会花费一些时间,因为每次更新都会导致对原始数组进行复制并修改该特定值。

IOArray是此类MArray的特定类型。因此,我们可以用writeArray :: (MArray a e m, Ix i) => a i e -> i -> e -> m ()定义modifyArray

modifyArray :: IOArray Int Char -> Int -> IO (IOArray Int Char)
modifyArray arr idx | i < 0 = return arr
                    | mod i 102 == 1 = writeArray arr idx ' ' >> return arr
                    | otherwise = modifyarr arr idx

请注意,这里不必返回数组,从本质上讲,IOArray可以看作是对可变数组的引用,因此在writeArray操作之后,arr指的是修改后的数组。如果您在较大的IO操作中使用此数组,则在modifyArray之后,将修改该数组。

您在此处使用循环来获取具有i且小于或等于初始索引的最大索引div i 102 == 1。但是,您可以通过减去模的结果来改善这一点:

modifyArray :: IOArray Int Char -> Int -> IO (IOArray Int Char)
modifyArray arr idx | i < 0 = return arr
                    | otherwise = writeArray arr (idx - mod (idx-1) 102) ' ' >> return arr