Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 如何在haskell中使用特定索引在2D列表中添加数字_List_Haskell - Fatal编程技术网

List 如何在haskell中使用特定索引在2D列表中添加数字

List 如何在haskell中使用特定索引在2D列表中添加数字,list,haskell,List,Haskell,我是haskell的初学者,我试着在二维列表中添加一个数字,在haskell中有特定的索引,但我不知道怎么做 我举了一个例子: [[],[],[]] 我想在索引1中加一个数字(3),如下所示 [[],[3],[]] 我试过这个 [array !! 1] ++ [[3]] 但是它不起作用正如您在迄今为止的尝试中可能已经注意到的,Haskell不像其他许多语言那样,因为它通常是不可变的,因此尝试更改值,特别是在这样的深度嵌套结构中,并不是一件容易的事情[array!!1]将为您提供一个嵌套列表

我是haskell的初学者,我试着在二维列表中添加一个数字,在haskell中有特定的索引,但我不知道怎么做

我举了一个例子:

[[],[],[]]
我想在索引1中加一个数字(3),如下所示

[[],[3],[]]
我试过这个

[array !! 1] ++ [[3]]

但是它不起作用

正如您在迄今为止的尝试中可能已经注意到的,Haskell不像其他许多语言那样,因为它通常是不可变的,因此尝试更改值,特别是在这样的深度嵌套结构中,并不是一件容易的事情
[array!!1]
将为您提供一个嵌套列表
[[]]
,但这是不可变的,因此您对该结构所做的任何操作都不会反映在原始
数组中,它将是一个单独的副本

(有一些特殊的环境,您可以在其中执行局部可变性,例如ST monad中的向量,但这是一个例外。)

对于您尝试执行的操作,您必须解构列表,使其达到可以轻松进行修改的程度,然后从(修改的)部分重建最终结构

splitAt
函数似乎可以帮助您实现这一点:它获取一个列表,并在您给定的索引处将其分成两部分

let array = [[],[],[]]
splitAt 1 array
我会给你

([[]], [[],[]])
这有助于您更接近所需的列表,即中间嵌套列表

让我们进行一次解构绑定,以便以后能够重建最终列表:

let array = [[],[],[]]
    (beginning, end) = splitAt 1 array
接下来,您需要获得所需的子列表,它是
结束
列表中的第一项:

    desired = head end
现在您可以进行修改了--注意,这将生成一个新列表,它不会修改其中的列表:

    desired' = 3:desired
现在我们需要把它放回
end
列表中。不幸的是,
结束
列表仍然是
[[],[]]
的原始值,因此我们必须用我们的
所需的“
替换此列表的开头,以使其正确:

    end' = desired' : (tail end)
这会在开始处删除空的子列表,并将修改后的列表附加到其位置

现在只剩下将修改后的
end'
与原始的
开头重新组合:

in beginning ++ end'
制作整个片段:

let array = [[],[],[]]
    (beginning, end) = splitAt 1 array
    desired = head end
    desired' = 3:desired
    end' = desired' : (tail end)
in beginning ++ end'
或者,如果您在REPL中输入所有这些命令:

let array = [[],[],[]]
let (beginning, end) = splitAt 1 array
let desired = head end
let desired' = 3:desired
let end' = desired' : (tail end)
beginning ++ end'
正如我们所知,Haskell中的事物是不可变的。您要做的不是就地修改列表,而是通过分解列表结构、转换其中一个部分以及使用此更改的部分重新构造列表。其中提出了一种解构方式(通过
splitAt
);我想再给你一个

Haskell中的列表定义如下:

data[]a=[]a:[a]
这表示“一个
A
列表要么为空,要么是一个
A
,后跟一个
A
列表”
(:)
读作“cons”表示“constructor”,您可以使用它创建非空列表

1:[]->[1]
1 : [2,3]         -> [1,2,3]
1 : 2 : 3 : []    -> [1,2,3]
由于模式匹配,这是双向的。如果您有一个列表
[1,2,3]
,将它与
x:xs
匹配将把它的头
1
绑定到名称
x
,把它的尾
[2,3]
绑定到
xs
。如您所见,我们已将列表分解为最初用于创建它的两部分。然后,我们可以在重新整理列表之前对这些部分进行操作:

λ>设x:xs=[1,2,3]
λ> 设y=x-5
λ> y:xs
[-4,2,3]
因此,在您的情况下,我们可以将初始列表与
x:y:z:[]
,计算
w=y++[3]
,并构建新列表:

λ>设x:y:z:[]=[],[],[]
λ> 设w=y++[3]
λ> [x,w,z]
[[],[3],[]]
但这不是很好的扩展性,也不能解决您提出的问题(“使用特定索引”)。如果稍后我们要更改列表的第千项,该怎么办?我不太喜欢搭配那么多的衣服。幸运的是,我们对list
xs中的list index
n
有一些了解,它是list
x:xs中的index
n+1
。因此,我们可以递归,沿着列表移动一步,并在每一步中递减索引:

foo::Int->[[Int]]->[[Int]]
foo0(x:xs)=TODO——索引0是x。我们到了;在这里,我们在重新构造列表之前先与[3]连接。
foo n(x:xs)=x:foo(n-1)xs
foon n[]=TODO——由您决定如何处理无效索引。考虑函数误差。
假设您是在索引0上操作,那么您自己实现这三个步骤中的第一个。确保您理解第二节中的递归调用。然后继续读下去

现在,这是可行的。虽然它对一个特定类型的列表中的指定项执行预先确定的计算,但它并不是那么有用。是概括的时候了。我们需要的是以下类型签名的函数:

bar::(a->a)->Int->[a]->[a]
其中
bar f n xs
将转换
f
应用于列表
xs
中索引
n
处的值。有了它,我们可以实现以前的功能:

foo n xs=bar(++[3])n xs
foo=bar(++[3])——或者,部分应用
信不信由你,将你已经编写的
foo
更改为更有用的
是一项非常简单的任务。试试看