关于列表,方括号和圆括号有什么区别?
What is the difference between square brackets and parentheses in regard to lists?
正如标题所暗示的,我不确定方括号和圆括号在列表方面的区别。
定义了 Haskell 的 insert
的两个版本,一个使用方括号,另一个使用圆括号:
insert' :: Int -> [Int] -> [Int]
insert' y [] = [y]
insert' y (x:xs) | y <= x = y:x:xs | otherwise = x : insert' y xs
----
insert' y [x:xs] | y <= x = y:x:xs | otherwise = x : insert' y xs
insert'
的第二个定义不起作用的原因是什么?
它给出的错误消息,对于任何想知道的人:
test.hs:3:12: error:
• Couldn't match expected type ‘Int’ with actual type ‘[Int]’
• In the pattern: x : xs
In the pattern: [x : xs]
In an equation for ‘insert'’:
insert' y [x : xs]
| y <= x = y : x : xs
| otherwise = x : insert' y xs
|
3 | insert' y [x:xs] | y <= x = y:x:xs | otherwise = x : insert' y xs
|
(x:xs)
作为模式将匹配任何具有 x
头部和 xs
尾部的非空列表。
[x:xs]
作为模式将匹配单例列表——一个只包含一个项目的列表——这是一个非空列表,匹配模式 (x:xs)
。模式 [x:xs]
实际上等同于模式 [(x:xs)]
。这是一个 嵌套 模式,并且 Haskell 允许这样做。外部模式匹配单例列表,内部模式匹配非空列表。该位置的括号是可选的。
这就是为什么您的第二个定义暗示第二个参数的类型是 [[a]]
,但您已将其声明为 [Int]
。而 Int
无法匹配 [a]
。 (a
也被确定为 Int
,因为您比较 x
和 y
,而 y
第一个参数被声明为 Int
,但这并没有改变任何东西)。
[ [a] ]
[ Int ]
----------------
***mismatch***
与几乎所有其他语言一样,Haskell 中的括号实际上 做 任何事情。它们帮助解析器知道您打算将哪些内容组合在一起,仅此而已;它们不会改变其中内容的含义,如果解析器可以神奇地猜出您打算在每个选择点将事物分组的方式,我们根本不需要它们。所以所有这些模式的行为 完全 相同:
x
(x)
((x))
(((((((((x)))))))))
所有这些模式也完全相同:
x:xs
(x:xs)
((x:xs))
(((((((((x:xs)))))))))
有时我们必须使用后面的一个——比如(x:xs)
——而不是第一个——x:xs
——来通知解析器我们打算将这些东西分组一起。但是括号不会改变模式的含义。
另一方面,方括号用于构造列表。它们具有实际的 运行 时间含义:它们在内存中分配一个新的数据结构并对其进行初始化。例如,3
是一个数字,但 [3]
是一个包含单个元素的列表,[3,4]
是一个包含两个元素的列表,[[3]]
是一个列表列表,并且很快。相同的行为适用于模式:
x -- match anything (even a list!) and bind x to its value
[x] -- match a list with a single element, and bind x to that element's value
[x,y] -- match a list with two elements, and bind x and y to those elements' values
[[x]] -- match a nested list; the outer and inner lists both have one element; bind x to the first element's first element
现在我们可以解决您的具体示例。模式 x:xs
是一种模式,它匹配具有至少一个元素的任何列表,将 x
绑定到第一个元素,将 xs
绑定到列表的其余部分。模式 (x:xs)
的作用完全相同。另一方面,模式 [x:xs]
匹配只有一个元素的列表,因为有方括号;然后将该列表的唯一元素与模式 x:xs
匹配,行为如上所述。
这样做的一个结果是 x:xs
可以匹配具有任何类型元素的列表——例如,Int
——但是 [x:xs]
只能匹配其元素是列表的列表。
正如标题所暗示的,我不确定方括号和圆括号在列表方面的区别。
定义了 Haskell 的 insert
的两个版本,一个使用方括号,另一个使用圆括号:
insert' :: Int -> [Int] -> [Int]
insert' y [] = [y]
insert' y (x:xs) | y <= x = y:x:xs | otherwise = x : insert' y xs
----
insert' y [x:xs] | y <= x = y:x:xs | otherwise = x : insert' y xs
insert'
的第二个定义不起作用的原因是什么?
它给出的错误消息,对于任何想知道的人:
test.hs:3:12: error:
• Couldn't match expected type ‘Int’ with actual type ‘[Int]’
• In the pattern: x : xs
In the pattern: [x : xs]
In an equation for ‘insert'’:
insert' y [x : xs]
| y <= x = y : x : xs
| otherwise = x : insert' y xs
|
3 | insert' y [x:xs] | y <= x = y:x:xs | otherwise = x : insert' y xs
|
(x:xs)
作为模式将匹配任何具有 x
头部和 xs
尾部的非空列表。
[x:xs]
作为模式将匹配单例列表——一个只包含一个项目的列表——这是一个非空列表,匹配模式 (x:xs)
。模式 [x:xs]
实际上等同于模式 [(x:xs)]
。这是一个 嵌套 模式,并且 Haskell 允许这样做。外部模式匹配单例列表,内部模式匹配非空列表。该位置的括号是可选的。
这就是为什么您的第二个定义暗示第二个参数的类型是 [[a]]
,但您已将其声明为 [Int]
。而 Int
无法匹配 [a]
。 (a
也被确定为 Int
,因为您比较 x
和 y
,而 y
第一个参数被声明为 Int
,但这并没有改变任何东西)。
[ [a] ]
[ Int ]
----------------
***mismatch***
与几乎所有其他语言一样,Haskell 中的括号实际上 做 任何事情。它们帮助解析器知道您打算将哪些内容组合在一起,仅此而已;它们不会改变其中内容的含义,如果解析器可以神奇地猜出您打算在每个选择点将事物分组的方式,我们根本不需要它们。所以所有这些模式的行为 完全 相同:
x
(x)
((x))
(((((((((x)))))))))
所有这些模式也完全相同:
x:xs
(x:xs)
((x:xs))
(((((((((x:xs)))))))))
有时我们必须使用后面的一个——比如(x:xs)
——而不是第一个——x:xs
——来通知解析器我们打算将这些东西分组一起。但是括号不会改变模式的含义。
另一方面,方括号用于构造列表。它们具有实际的 运行 时间含义:它们在内存中分配一个新的数据结构并对其进行初始化。例如,3
是一个数字,但 [3]
是一个包含单个元素的列表,[3,4]
是一个包含两个元素的列表,[[3]]
是一个列表列表,并且很快。相同的行为适用于模式:
x -- match anything (even a list!) and bind x to its value
[x] -- match a list with a single element, and bind x to that element's value
[x,y] -- match a list with two elements, and bind x and y to those elements' values
[[x]] -- match a nested list; the outer and inner lists both have one element; bind x to the first element's first element
现在我们可以解决您的具体示例。模式 x:xs
是一种模式,它匹配具有至少一个元素的任何列表,将 x
绑定到第一个元素,将 xs
绑定到列表的其余部分。模式 (x:xs)
的作用完全相同。另一方面,模式 [x:xs]
匹配只有一个元素的列表,因为有方括号;然后将该列表的唯一元素与模式 x:xs
匹配,行为如上所述。
这样做的一个结果是 x:xs
可以匹配具有任何类型元素的列表——例如,Int
——但是 [x:xs]
只能匹配其元素是列表的列表。