当您使用x:xs语法拆分列表时,为什么它包含在括号中?圆括号的意义是什么?为什么不是[x:xs]或只是x:xs?
答案 0 :(得分:45)
cons单元格不必在每个上下文中都有括号,但在大多数情况下都是因为
用火信将它烧成大脑。
示例:
length [] = 0
length (x:xs) = 1 + length xs
如果省略括号,编译器会认为你有一个参数x
后面跟一个不合适的中缀运算符,它会痛苦地抱怨。另一方面,这没关系
length l = case l of [] -> 0
x:xs -> 1 + length xs
在这种情况下,x
和xs
都不可能被解释为功能应用程序的一部分,因此不需要括号。
请注意,相同的精彩规则函数应用程序比任何中缀运算符更紧密是允许我们在length xs
中编写1 + length xs
而没有任何括号。中缀规则给予和中缀规则取消。
答案 1 :(得分:14)
您只是使用优先级较低的cons运算符:
。需要括号以使事情保持正确。
并且您不使用[x:xs]
,因为这会匹配一个列表,该列表的唯一元素是包含头x
和尾xs
的列表。
答案 2 :(得分:3)
我不知道确切的答案,但我想这是因为模式中可以匹配的东西。只能构建器匹配。构造函数可以是单个单词或复合词。看下一个代码:
data Foo = Bar | Baz Int
f :: Foo -> Int
f Bar = 1
f (Baz x) = x - 1
单字构造函数按原样匹配。但复合构造函数必须用parens包围,以避免歧义。如果我们跳过parens,它看起来像是匹配两个独立的参数:
f Baz x = x - 1
所以,由于(:)
是复合的,所以它必须是parens。跳过Bar
的parens是一种语法糖。
更新:我意识到(正如sykora所说),这是运营商优先权的结果。它澄清了我的假设。函数应用程序(它只是函数和参数之间的空格)具有最高优先级。其他包括(:)的优先级较低。因此,f x:xs
应被解释为((:) (f x)) xs
,这可能不是我们所需要的。虽然f (x:xs)
被解释为f
已应用于x:xs
,而(:)
已应用于x
和xs
。
答案 3 :(得分:2)
与解析有关。
请记住,冒号:只是一个用运算符语法编写的构造函数。所以像
这样的功能foo [] = 0
foo (x:xs) = x + foo xs
也可以写成
foo [] = 0
foo ((:) x xs) = x + foo xs
如果在最后一行中删除括号,则解析起来非常困难!
答案 4 :(得分:1)
:
是一个数据构造函数,与任何其他模式匹配一样,但是写入了中缀。由于中缀优先,括号纯粹存在;它们实际上不是必需的,并且在优先规则允许时可以安全地省略。例如:
> let (_, a:_) = (1, [2, 3, 4]) in a
2
> let a:_ = "xyzzy"
'x'
> case [1, 2, 3] of; a:b -> a; otherwise -> 0;
1
有趣的是,这似乎并不适用于lambda的头脑。不知道为什么。
与往常一样,“并置”运算符比其他任何运算符都更紧密,因此通常需要分隔符,但它们实际上并不是模式匹配的部分 - 否则你不会我可以使用(x:y:zs)
之类的模式而不是(x:(y:zs))
。