Pradeep
Pradeep

Reputation: 4127

What do the parentheses signify in (x:xs) when pattern matching?

when you split a list using x:xs syntax why is it wrapped in a parentheses? what is the significance of the parentheses? why not [x:xs] or just x:xs?

Upvotes: 32

Views: 12201

Answers (5)

Norman Ramsey
Norman Ramsey

Reputation: 202655

The cons cell doesn't have to be parenthesized in every context, but in most contexts it is because

Function application binds tighter than any infix operator.

Burn this into your brain in letters of fire.

Example:

length [] = 0
length (x:xs) = 1 + length xs

If parentheses were omitted the compiler would think you had an argument x followed by an ill-placed infix operator, and it would complain bitterly. On the other hand this is OK

length l = case l of [] -> 0
                     x:xs -> 1 + length xs

In this case neither x nor xs can possibly be construed as part of a function application so no parentheses are needed.

Note that the same wonderful rule function application binds tighter than any infix operator is what allows us to write length xs in 1 + length xs without any parentheses. The infix rule giveth and the infix rule taketh away.

Upvotes: 50

C. A. McCann
C. A. McCann

Reputation: 77404

: is a data constructor, like any other pattern match, but written infix. The parentheses are purely there because of infix precedence; they're actually not required and can be safely omitted when precedence rules allow. For instance:

> let (_, a:_) = (1, [2, 3, 4]) in a
2
> let a:_ = "xyzzy"
'x'
> case [1, 2, 3] of; a:b -> a; otherwise -> 0;
1

Interestingly, that doesn't seem to work in the head of a lambda. Not sure why.

As always, the "juxtaposition" operator binds tighter than anything else, so more often than not the delimiters are necessary, but they're not actually part of the pattern match--otherwise you wouldn't be able to use patterns like (x:y:zs) instead of (x:(y:zs)).

Upvotes: 1

Rorick
Rorick

Reputation: 8953

I don't know exact answer, but I guess that is due to what can be matched in patterns. Only constructors can be matched. Constructors can be of single word or composite. Look at the next code:

data Foo = Bar | Baz Int

f :: Foo -> Int
f Bar     = 1
f (Baz x) = x - 1

Single word constructors match as is. But composite constructors must be surrounded with parens in order to avoid ambiguity. If we skip parens it looks like matching against two independent arguments:

f Baz x = x - 1

So, as (:) is composite it must be in parens. Skipping parens for Bar is a kind of syntactic sugar.

UPDATE: I realized that (as sykora noted) it is a consequence of operator precedence. It clarifies my assumptions. Function application (which is just space between function and argument) has highest precedence. Others including (:) have lower precedence. So f x:xs is to be interpreted as ((:) (f x)) xs that is presumably not what we need. While f (x:xs) is interpreted as f applied to x:xs which is in turn (:) applied to x and xs.

Upvotes: 3

yatima2975
yatima2975

Reputation: 6610

It's to do with parsing.

Remember, the colon : is just a constructor that's written with operator syntax. So a function like

foo [] = 0
foo (x:xs) = x + foo xs

could also be written as

foo [] = 0
foo ((:) x xs) = x + foo xs

If you drop the parenthesis in that last line, it becomes very hard to parse!

Upvotes: 2

sykloid
sykloid

Reputation: 101346

You're simply using the cons operator :, which has low precedence. Parentheses are needed so that things stay right.

And you don't use [x:xs], because that would match a list whose only element is a list with head x and tail xs.

Upvotes: 15

Related Questions