List 使用';向列表开头添加内容:';Haskell中的操作员

List 使用';向列表开头添加内容:';Haskell中的操作员,list,haskell,recursion,functional-programming,where,List,Haskell,Recursion,Functional Programming,Where,几天前我开始学习Haskell,复习了基础知识,还有一些东西我搞不懂 首先,, 在GHCi控制台中,当我尝试使用“:”操作符向列表的开头添加某些内容时,仅当我尝试添加单个文本而不是列表时,它才起作用。(5:[1,2,3,4])可以工作,但([1,2]:[3,4,5])不行。但是,有这样一个功能: replicate2 n x | n <= 0 = [] | otherwise = x:replicate2 (n-1) x 函数返回[[1,2],[1,2]] 我的问题:这是如何工作的

几天前我开始学习Haskell,复习了基础知识,还有一些东西我搞不懂

首先,, 在GHCi控制台中,当我尝试使用“:”操作符向列表的开头添加某些内容时,仅当我尝试添加单个文本而不是列表时,它才起作用。(
5:[1,2,3,4]
)可以工作,但(
[1,2]:[3,4,5]
)不行。但是,有这样一个功能:

replicate2 n x
| n <= 0    = []
| otherwise = x:replicate2 (n-1) x
函数返回
[[1,2],[1,2]]

我的问题:这是如何工作的?哈斯克尔难道不应该发疯,说出错误吗?当我尝试在GHCi中这样做时,它会这样做

我的问题:这是如何工作的?我不明白为什么,因为它不应该

你错了,因为它不应该这样,你错了,因为你忘记了
a
也可能意味着
[a]

让我们看一些类型方程:

[]          :: [a]
(:)         :: a -> [a] -> [a]
[1,2,3]     :: [Int]
0 : [1,2,3] :: [Int]
现在有一个转折:

[]                 :: [[a]]
(:)                :: [a] -> [[a]] -> [[a]]
[[1,2], [3]]       :: [[Int]]
[0] : [[1,2], [3]] :: [[Int]]

列表列表仍然是一个列表,其中添加了
的元素是。。。一份清单。

好吧,让我们回顾一些事情。
运算符的主体(=最通用)类型如下:

(:) :: a -> [a] -> [a]
a
是一个类型变量。这整件事的意思是,每次实际使用操作符时,它的使用上下文决定了在该特定使用中
a
将代表什么类型。因此,如果您正在这样做:

example1 :: [Integer]
example1 = 5 : [1, 2]
example2 :: [[Integer]]
example2 = [1,2] : [[1,2]]
…在该上下文中,
a
Integer
,如果执行此操作:

example1 :: [Integer]
example1 = 5 : [1, 2]
example2 :: [[Integer]]
example2 = [1,2] : [[1,2]]
…那么在该上下文中,
a
[Integer]
。因此,类型的含义是:

(:) :: a -> [a] -> [a]
…就是您放在列表顶部的值的类型
a
,必须与放入该列表的值的类型相同。如果它是一个元素为
Integer
s的列表,那么该值也必须是
Integer
。在这个让你困惑的例子中,我们有一个
整数
的列表,所以在这个上下文中
的第一个参数:
是一个
整数
的列表

Haskell对此非常精确,因此我们可以继续使用其他示例来说明相同的原理。例如,在这里,我们将列表列表放在列表列表列表的前面:

example3 :: [[[Integer]]]
example3 = [[1, 2], [3, 4]] : [[[1, 2]]]
-- Value: [[[1, 2], [3, 4]], [[1, 2]]] 
因此,再次转到主要类型的

(:) :: a -> [a] -> [a]

另一种看待它的方式是,作为一种模式,
的所有用法都必须遵循:第一个参数的类型必须比第二个参数的类型和结果少一对方括号。它告诉我们的另一件事是,
不关心什么类型的
a
,它可能是一个简单的值,比如
整数,也可能是一些复杂的东西,比如
[[[[[[Integer]]]]]
,而这个函数就是不能区分它们之间的区别。

这个
(:)
操作员将一项添加到列表的开头。这就是为什么
1:[2,3,4]
可以,但是
[1,2]:[3,4]
不行;您试图在前面添加一个列表。是的,没错,我的问题是关于我提供的功能。它确实有效,我不明白为什么,因为它不应该。如果你正在构建一个列表列表,那么列表就是“一项”。如果这有意义的话……请注意,您可以使用
1:2:[3,4,5]
,因为它具有正确的关联性。
[1,2]:[1,2]:[]
在ghci中应该可以正常工作。好的,现在更清楚了,但仍然可以。在函数replicate2中,我不在任何地方定义我构建列表列表的位置。如果在CHCI中尝试类似5:6的内容,它不会自动生成列表[5,6],它会抛出错误。如果我尝试[1,2]:[3,4]它会自动执行[1,2],[3,4]。但是在这个函数中,我基本上是这样做的:[1,2]:[1,2]:[],它返回[[1,2],[1,2]]。你不明白我的意思吗?如果您查看replicate2函数,它将列表添加到列表中,但不会将列表添加到列表列表中。这个魔法是怎么发生的?哦不。。等等,如果我用:t检查函数类型定义,它会说:replicate2::(numi,ordi)=>i->a->[a]。那么它的定义是返回一个列表,因为我在列表中添加了列表,所以它返回一个列表列表?我想我明白了。@EasternDude你说:“如果我尝试[1,2]:[3,4]它不起作用,但这个函数实际上是在做[1,2]:[1,2]:[]”。好吧,最后那额外的
:[]
让一切都不同了!使用
[1,2]:[3,4]
,您试图将
[1,2]
元素添加到列表中,元素
3
4
,并且
[1,2]
3
具有不同的类型。但是使用
[1,2]:[1,2]:[]
,首先将元素
[1,2]
添加到没有元素的列表中(因此还没有类型不匹配),然后将元素
[1,2]
添加到只有一个元素的列表中,
[1,2]
。它们具有相同的类型,因此没有类型不匹配。