修改Haskell 2D数组的元素

时间:2014-12-31 01:31:15

标签: arrays list haskell concatenation

我正在编写一个函数来修改给定2D“数组”的元素,如下所示:

change_elem :: Int -> Int -> a -> [[a]] -> [[a]]
-- empty list case
change_elem _ _ _ [] = []

-- have arrived at the element to change`
change_elem 0 0 x ((y:ys):ls) = (x:ys):ls

-- reduce the column until we find the element to change
change_elem 0 col x ((y:ys):ls) = [[y]] ++ change_elem 0 (col-1) x (ys:ls)

-- reduce the row until we find the column to change
change_elem row col x (l:ls) = l : change_elem (row-1) col x ls

适用于change_elem 1 0 3 [[1,2],[4,5]]等输入并生成[[1,2],[3,5]]。但是,我的问题是当我尝试更改不在第0列中的元素时,问题显然在于“减少列”步骤。

change_elem 2 1 7 [[1,2,3],[4,5,6],[1,2,0]]给出输出 [[1,2,3],[4,5,6],[1],[7,0]]。它的行为是它将给定行的早期元素分成单个列表。

change_elem 0 4 10 [[0,1,2,3,4,5,6]]收益[[0],[1],[2],[3],[10,5,6]]

(++)运算符不应该将先前的元素返回到列表中,只留下一个统一的行吗?

我尝试在结果列表中调用concat,但是当我修改行以读取:

... concat $ [[y]] ++ change_elem 0 (col-1) x (ys:ls)

我得到一个很长的错误,但似乎这应该有效。 错误:

Couldn't match expected type ‘[a]’ with actual type ‘a’
  ‘a’ is a rigid type variable bound by
      the type signature for
        change_elem :: Int -> Int -> a -> [[a]] -> [[a]]
      at test.hs:15:16
Relevant bindings include
  ls :: [[a]] (bound at test.hs:23:29)
  ys :: [a] (bound at test.hs:23:25)
  y :: a (bound at test.hs:23:23)
  x :: a (bound at test.hs:23:19)
  change_elem :: Int -> Int -> a -> [[a]] -> [[a]]
    (bound at test.hs:17:1)
In the expression: y
In the expression: [y]

1 个答案:

答案 0 :(得分:2)

不,++运算符不会这样做。它简单地将两个列表连接在一起。使用[[1]] ++ [[2]],您可以说x = [1]y = [2],然后通过直接替换获得[x] ++ [y][x, y][[1], [2]]

至于解决当前问题,我建议编写一个可以替换简单列表中索引元素的函数,如

replace :: Int -> a -> [a] -> [a]
replace i x xs = ???

然后,您可以非常简单地将change_elem实现为

change_elem row col x xs =
    let row_to_replace_in = xs !! row
        modified_row = replace col x row_to_replace_in
    in replace row modified_row xs

这当然不是最有效或最安全的实现,但它是一个非常简单的实现。

您在使用concat时看到错误的原因是因为您正在将[[Int]]类型的某些内容转换为[Int],但您已经#39 ; ve告诉编译器你的函数必须返回[[Int]]类型的东西(当提供Int矩阵时)。