Подтвердить что ты не робот

Что означают круглые скобки (x: xs) при сопоставлении шаблонов?

когда вы разбиваете список с помощью синтаксиса x: xs, почему он заключен в круглые скобки? Каково значение круглых скобок? почему не [x: xs] или просто x: xs?

4b9b3361

Ответ 1

Ячейка 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 без каких-либо круглых скобок. Правило инфикса дается, и правило инфикса удаляется.

Ответ 2

Вы просто используете оператор cons :, который имеет низкий приоритет. Скобки необходимы, чтобы все оставалось в порядке.

И вы не используете [x:xs], потому что это будет соответствовать списку, единственным элементом которого является список с головой x и хвостом xs.

Ответ 3

Я не знаю точного ответа, но я думаю, это связано с тем, что можно сопоставить в шаблонах. Только конструкторы могут быть сопоставлены. Конструкторы могут быть однословными или составными. Посмотрите на следующий код:

data Foo = Bar | Baz Int

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

Конструкторы с одним словом соответствуют как есть. Но составные конструкторы должны быть окружены паранами, чтобы избежать двусмысленности. Если мы пропустим parens, это похоже на сопоставление с двумя независимыми аргументами:

f Baz x = x - 1

Итак, поскольку (:) является составным, он должен быть в parens. Пропуск паров для Bar - это своего рода синтаксический сахар.

UPDATE: я понял, что (как заметил сикора) это следствие приоритета оператора. Он разъясняет мои предположения. Функция-приложение (которое представляет собой просто пространство между функцией и аргументом) имеет наивысший приоритет. Другие, включая (:) имеют более низкий приоритет. Поэтому f x:xs следует интерпретировать как ((:) (f x)) xs, который, по-видимому, не тот, который нам нужен. Пока f (x:xs) интерпретируется как f, примененный к x:xs, который, в свою очередь, (:) применяется к x и xs.

Ответ 4

Это связано с разбором.

Помните, что двоеточие: это просто конструктор, написанный с синтаксисом оператора. Таким образом, функция типа

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

также может быть записано как

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

Если вы отпустите круглую скобку в этой последней строке, становится очень сложно разобрать!

Ответ 5

: - это конструктор данных, как и любое другое совпадение шаблонов, но записанный инфикс. Скобки заключаются исключительно из-за префикса infix; они фактически не требуются и могут быть безопасно опущены, если позволяют правила приоритета. Например:

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

Интересно, что это не работает в голове лямбда. Не знаю, почему.

Как всегда, оператор "сопоставления" привязывается сильнее, чем что-либо еще, поэтому чаще всего нужны разделители, но они фактически не являются частью совпадения шаблонов - иначе вы не сможете использовать шаблоны например (x:y:zs) вместо (x:(y:zs)).