我正在编写一个函数来修改给定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]
答案 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
矩阵时)。