Выражения
За исключением let -выражений эти трансляции сохраняют и статическую, и динамическую семантику. Свободные переменные и конструкторы, используемые в этих трансляциях, всегда ссылаются на сущности, определенные в Prelude. Например, "concatMap", используемая в трансляции описания списка (раздел "3.11" ), обозначает concatMap, определенную в Prelude, невзирая на то, находится ли идентификатор "concatMap" в области видимости, где используется описание списка, и (если находится в области видимости) к чему он привязан.
В синтаксисе, который следует далее, есть некоторые семейства нетерминалов, индексированные уровнями приоритета (записанными как верхний индекс). Аналогично, нетерминалы op (оператор), varop (оператор-переменной) и conop (оператор-конструктора) могут иметь двойной индекс: букву l, r или n соответственно для левоассоциативности, правоассоциативности или отсутствия ассоциативности и уровень приоритета. Переменная уровня приоритета i изменяется в пределах от 0 до 9, переменная ассоциативности a изменяется в диапазоне {l, r, n}. Например,
на самом деле обозначает 30 правил вывода с 10 подстановками для i и 3 для a.
Перевод:
выражение | -> -> | выражение^0 :: [контекст => ] тип | (сигнатура типа выражения) |
| | выражение0 | ||
выражениеi | -> | выражениеi+1 [квалифицированный-оператор(n,i) выражениеi+1] | |
| | левое-сечение-выраженияi | ||
| | правое-сечение-выраженияi | ||
левое-сечение-выраженияi | -> | (левое-сечение-выраженияi | выражениеi+1) квалифицированный-оператор(l,i) выражениеi+1 | |
левое-сечение-выражения6 | -> | - выражение7 | |
правое-сечение-выраженияi | -> | выражениеi+1 квалифицированный-оператор(r,i) (правое-сечение-выраженияi | выражениеi+1) | |
выражение10 | -> | \ такой-как-образец1 ... такой-как-образецn -> выражение | (лямбда-абстракция, n>= 1) |
| | let списки-объявлений in выражение | ( let -выражение) | |
| | if выражение then выражение else выражение | (условное выражение) | |
| | case выражение of { список-альтернатив } | ( case -выражение) | |
| | do { список-инструкций } | ( do -выражение) | |
| | функциональное-выражение | ||
функциональное-выражение | -> | [функциональное-выражение] выражение-аргумента | (применение функции) |
выражение-аргумента | -> | квалифицированная-переменная | (переменная) |
| | общий-конструктор | (общий конструктор) | |
| | литерал | (выражение в скобках) | |
| | ( выражение ) | ||
| | ( выражение1 , ... , выражениеk ) | (кортеж, k>= 2) | |
| | [ выражение1 , ... , выражениеk ] | (список, k >= 1) | |
| | [ выражение1 [, выражение2] .. [выражение3] ] | (арифметическая последовательность) | |
| | [ выражение | квалификатор1 , ... , квалификаторn ] | (описание списка, n >= 1) | |
| | ( выражениеi+1 квалифицированный-оператор(a,i) ) | (левое сечение) | |
| | ( левое-сечение-выраженияi квалифицированный-оператор(l,i) ) | (левое сечение) | |
| | ( квалифицированный-оператор(a,i)<-> выражениеi+1 ) | (правое сечение) | |
| | ( квалифицированный-оператор(r,i)<-> правое-сечение-выраженияi ) | (правое сечение) | |
| | квалифицированный-конструктор { связывание-имени-поля1 , ... , связывание-имени-поляn } | (именованная конструкция, n>=0) | |
| | выражение-аргумента<квалифицированный-конструктор> { связывание-имени-поля1 , ... , связывание-имени-поляn } | (именованное обновление, n>=1) |
Неоднозначность выражений, включая инфиксные операторы, разрешается с помощью ассоциативности и приоритета оператора (см. раздел "4.4.2" ). Следующие друг за другом операторы без скобок, имеющие один и тот же приоритет, должны быть оба либо левоассоциативными, либо правоассоциативными, во избежание синтаксической ошибки. Для заданного выражения без скобок "x qop(a,i) y qop(b,j) z", где qop - оператор, часть "x qop(a,i) y" или "y qop(b,j) z" следует взять в скобки, когда i=j, за исключением a=b=l или a=b=r.
Отрицание является единственным префиксным оператором в Haskell , он имеет тот же приоритет, что и инфиксный оператор -, определенный в Prelude (см. раздел " 4.4.2" ).
Грамматика является неоднозначной по отношению к пространству лямбда-абстракций, let-выражений и условных выражений. Неоднозначность разрешается с помощью мета-правила, согласно которому каждая из этих конструкций рассматривается слева направо насколько это возможно.
Примеры интерпретации при разборе показаны ниже.
Это | интерпретируется как |
---|---|
f x + g y | (f x) + (g y) |
- f x + y | (- (f x)) + y |
let { ... } in x + y | let { ... } in (x + y) |
z + let { ... } in x + y | z + (let { ... } in (x + y)) |
f x y :: Int | (f x y) :: Int |
\ x -> a+b :: Int | \ x -> ((a+b) :: Int) |
Замечание относительно разбора. Выражения, которые затрагивают взаимодействие ассоциативности и приоритетов с применением мета-правила для let/лямбда, могут оказаться трудными для разбора. Например, выражение
let x = True in x == x == True
не может означать
let x = True in (x == x == True)
потому что (==) является неассоциативным оператором, поэтому выражение должно быть интерпретировано таким образом:
(let x = True in (x == x)) == True
Тем не менее, реализации могут прекрасно обойтись дополнительным проходом после завершения разбора, чтобы обработать ассоциативность и приоритеты операторов, поэтому они могут спокойно передать предыдущий неправильный разбор. Мы советуем программистам избегать использования конструкций, чей разбор затрагивает взаимодействие (отсутствия) ассоциативности с применением мета-правила для let/лямбда.
Ради ясности остальная часть этого раздела описывает синтаксис выражений без указания их приоритетов.