2010-02-03 2 views
22

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

+0

У вас есть пример того, где он завернут()? x: xs может использоваться как для описания списка с первым элементом списка. [x: xs] будет списком со списком x: xs в нем. –

+0

Он говорит о сопоставлении с образцом, а не о создании списка. – Rorick

ответ

41

минусов клетка не должен быть в круглых скобках в любом контексте, но в большинстве контекстов это потому, что

Функция приложение связывает сильнее, чем любой оператор инфиксного.

Зажигайте это в своем мозгу буквами огня.

Пример:

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

+1 для писем огня. Мой код Haskell перестает выглядеть как Lisp после того, как я усвоил это правило. – Nefrubyr

+1

+1. Любите последнее предложение –

14

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

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

+1

Я никогда не пробовал этот конкретный шаблон '[x: xs]', но, конечно, вы правы; он совпадает с одним списком на верхнем уровне. Непринужденным обозначением шаблона будет: '((x: xs): [])'. –

3

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

data Foo = Bar | Baz Int 

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

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

f Baz x = x - 1 

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

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

2

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

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

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

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

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

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

1

: - это конструктор данных, как и любой другой шаблон, но написанный инфикс. Скобки заключаются исключительно из-за префикса 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)).

Смежные вопросы