Haskell - 追加到列表列表中的列表并更新列表列表 return

Haskell - Append to a list inside a list of lists and return the lists of lists updated

我花了数小时寻找将 [[a]] 操纵为 [[a]] 的方法,我认为这将是解决我的问题的最佳方法。问题包括将 a 附加到 [a] 和 returning [[a]] 以及新的更改。

例如:xs = [[a],[b],[c]]y = d.

我想将 y 附加到 xs!!0 。我不能使用 xs!!0 ++ y 因为它会 return 只是 [a,d],我知道这是因为 Haskell 的不变性。

我将如何着手将值附加到子列表并 returning 列表列表? - [[a,d],[b],[c]] 使用上面的示例来说明这一点。

let { xs = [[1]] ; y = 2 ; zs = [(xs!!0) ++ [y]] } in zs 是在 GHCi 提示符下尝试的一个示例。

它returns [[1,2]].

对于例如[[1],[2,3],[4]]之类的,我们可以做到

appendToFirst :: [[a]] -> a -> [[a]]
appendToFirst (xs:r) y  =  (xs ++ [y]) : r

这样

> appendToFirst [[1],[2,3],[4]] 0
[[1,0],[2,3],[4]]

等号左边的(xs:r)是一个模式.

等号右边( (...) : r)中的(:)是“cons”操作,数据构造函数,(:) :: t -> [t] -> [t].

xs 绑定到输入列表的“头部”,即它的第一个元素,并且 r 绑定到输入列表的其余部分,在模式中;因此 xs 的值用于创建列表的更新版本,第一个子列表通过在其末尾附加一个值来更改,而 r 保持原样。

xs ++ [y] 创建一个 new 实体,新列表,而 xsy 继续引用它们原来的旧值定义为。由于 Haskell 的值和变量是不可变的,正如您确实提到的那样。


编辑:如果你想在某个子列表的末尾添加新元素在中间,而不是如图所示的第一个上面,这可以用例如完成splitAt 函数,喜欢

appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y xs  =  
     let
        (a,b) = splitAt i xs
     in
        init a ++ [last a ++ [y]] ++ b

尝试一下:

> appendInTheMiddle 2 0 [[1],[2],[3],[4]]
[[1],[2,0],[3],[4]]

如果需要基于 0 的代码,则添加错误处理、边界检查和调整索引(顺便说一下,这将导致更简单、更快的代码),留作 reader.

在语法上,这可以通过“视图模式”进行简化,如

{-# LANGUAGE ViewPatterns #-}

appendInTheMiddle :: Int -> a -> [[a]] -> [[a]]
appendInTheMiddle i y (splitAt i -> (a,b))  =
        init a ++ [last a ++ [y]] ++ b