Синтаксис Haskell 98 Описание Haskell 98
наверх | назад | вперед | содержание | предметный указатель функций

9  Синтаксический справочник

9.1  Соглашения об обозначениях

Эти соглашения об обозначениях используются для представления синтаксиса:

[pattern] необязательный
{pattern} ноль или более повторений
(pattern) группировка
pat1 | pat2 выбор
pat<pat'> разность --- элементы, порождаемые с помощью pat,
за исключением элементов, порождаемых с помощью pat'
fibonacci терминальный синтаксис в машинописном шрифте

Повсюду используется BNF-подобный синтаксис, чьи правила вывода имеют вид:

nonterm -> alt1 | alt2 | ... | altn

Перевод:
нетерминал -> альтернатива1 | альтернатива2 | ... | альтернативаn

В синтаксисе, который следует далее, есть некоторые семейства нетерминалов, индексированные уровнями приоритета (записанными как верхний индекс). Аналогично, нетерминалы op (оператор), varop (оператор-переменной) и conop (оператор-конструктора) могут иметь двойной индекс: букву l, r или n соответственно для левоассоциативности, правоассоциативности или отсутствия ассоциативности и уровень приоритета. Переменная уровня приоритета i изменяется в пределах от 0 до 9, переменная ассоциативности a изменяется в диапазоне {l, r, n}. Например,

aexp -> ( expi+1 qop(a,i) )
на самом деле обозначает 30 правил вывода с 10 подстановками для i и 3 для a.

И в лексическом, и в контекстно-свободном синтаксисе есть некоторые неоднозначности, которые разрешаются посредством создания грамматических фраз наибольшей из возможных длины, действуя слева направо (в восходящем синтаксическом анализе при конфликте сдвиг - свертка выполняется сдвиг). В лексическом синтаксисе это правило "максимального потребления". В контекстно-свободном синтаксисе это означает, что условные выражения, let-выражения и лямбда-абстракции продолжаются вправо насколько возможно.

9.2  Лексический синтаксис

program -> {lexeme | whitespace }
lexeme -> qvarid | qconid | qvarsym | qconsym
| literal | special | reservedop | reservedid
literal -> integer | float | char | string
special -> ( | ) | , | ; | [ | ] | `| { | }
whitespace -> whitestuff {whitestuff}
whitestuff -> whitechar | comment | ncomment
whitechar -> newline | vertab | space | tab | uniWhite
newline -> return linefeed | return | linefeed | formfeed
return -> возврат каретки
linefeed -> перевод строки
vertab -> вертикальная табуляция
formfeed -> перевод страницы
space -> пробел
tab -> горизонтальная табуляция
uniWhite -> любой пробельный символ Unicode
comment -> dashes [ any<symbol> {any}] newline
dashes -> -- {-}
opencom -> {-
closecom -> -}
ncomment -> opencom ANYseq {ncomment ANYseq}closecom
ANYseq -> {ANY}<{ANY}( opencom | closecom ) {ANY}>
ANY -> graphic | whitechar
any -> graphic | space | tab
graphic -> small | large | symbol | digit | special | : | " | '
small -> ascSmall | uniSmall | _
ascSmall -> a | b | ... | z
uniSmall -> любая буква Unicode нижнего регистра
large -> ascLarge | uniLarge
ascLarge -> A | B | ... | Z
uniLarge -> любая буква Unicode верхнего регистра или заглавная
symbol -> ascSymbol | uniSymbol<special | _ | : | " | '>
ascSymbol -> ! | # | $ | % | & | * | + | . | / | < | = | > | ? | @
| \ | ^ | | | - | ~
uniSymbol -> любой символ или знак пунктуации Unicode
digit -> ascDigit | uniDigit
ascDigit -> 0 | 1 | ... | 9
uniDigit -> любая десятичная цифра Unicode
octit -> 0 | 1 | ... | 7
hexit -> digit | A | ... | F | a | ... | f

Перевод:
программа -> {лексема | пробельная-строка }
лексема -> квалифицированный-идентификатор-переменной
| квалифицированный-идентификатор-конструктора
| квалифицированный-символ-переменной
| квалифицированный-символ-конструктора
| литерал
| специальная-лексема
| зарезервированный-оператор
| зарезервированный-идентификатор
литерал -> целый-литерал
| литерал-с-плавающей-точкой
| символьный-литерал
| строковый-литерал
специальная-лексема -> ( | ) | , | ; | [ | ] | `| { | }
пробельная-строка -> пробельный-элемент {пробельный-элемент}
пробельный-элемент -> пробельный-символ
| комментарий
| вложенный-комментарий
пробельный-символ -> новая-строка
| вертикальная-табуляция
| пробел
| горизонтальная-табуляция
| пробельный-символ-Unicode
новая-строка -> возврат-каретки перевод-строки
| возврат-каретки
| перевод-строки
| перевод-страницы
комментарий -> тире [ любой-символ<символ> {любой-символ}] новая-строка
тире -> -- {-}
начало-комментария -> {-
конец-комментария -> -}
вложенный-комментарий -> начало-комментария ЛЮБАЯ-последовательность {вложенный-комментарий ЛЮБАЯ-последовательность}конец-комментария
ЛЮБАЯ-последовательность -> {ЛЮБОЙ-символ}<{ЛЮБОЙ-символ}( начало-комментария | конец-комментария ) {ЛЮБОЙ-символ}>
ЛЮБОЙ-символ -> графический-символ | пробельный-символ
любой-символ -> графический-символ
| пробел
| горизонтальная-табуляция
графический-символ -> маленькая-буква
| большая-буква
| символ
| цифра
| специальная-лексема
| : | " | '
маленькая-буква -> маленькая-буква-ASCII
| маленькая-буква-Unicode
| _
маленькая-буква-ASCII -> a | b | ... | z
большая-буква -> большая-буква-ASCII | большая-буква-Unicode
большая-буква-ASCII -> A | B | ... | Z
символ -> символ-ASCII
| символ-Unicode<специальная-лексема | _ | : | " | '>
символ-ASCII -> ! | # | $ | % | & | * | + | . | / | < | = | > | ? | @
| \ | ^ | | | - | ~
символ-Unicode -> любой символ или знак пунктуации Unicode
цифра -> цифра-ASCII | цифра-Unicode
цифра-ASCII -> 0 | 1 | ... | 9
цифра-Unicode -> любая десятичная цифра Unicode
восьмиричная-цифра -> 0 | 1 | ... | 7
шестнадцатиричная-цифра -> цифра | A | ... | F | a | ... | f

varid -> (small {small | large | digit | ' })<reservedid>
conid -> large {small | large | digit | ' }
reservedid -> case | class | data | default | deriving | do | else
| if | import | in | infix | infixl | infixr | instance
| let | module | newtype | of | then | type | where | _
varsym -> ( symbol {symbol | :})<reservedop | dashes>
consym -> (: {symbol | :})<reservedop>
reservedop -> .. | : | :: | = | \ | | | <- | -> | @ | ~ | =>
varid (переменные)
conid (конструкторы)
tyvar -> varid (переменные типов)
tycon -> conid (конструкторы типов)
tycls -> conid (классы типов)
modid -> conid (модули)
qvarid -> [ modid . ] varid
qconid -> [ modid . ] conid
qtycon -> [ modid . ] tycon
qtycls -> [ modid . ] tycls
qvarsym -> [ modid . ] varsym
qconsym -> [ modid . ] consym
decimal -> digit{digit}
octal -> octit{octit}
hexadecimal -> hexit{hexit}
integer -> decimal
| 0o octal | 0O octal
| 0x hexadecimal | 0X hexadecimal
float -> decimal . decimal [exponent]
| decimal exponent
exponent -> (e | E) [+ | -] decimal
char -> ' (graphic<' | \> | space | escape<\&>) '
string -> " {graphic<" | \> | space | escape | gap}"
escape -> \ ( charesc | ascii | decimal | o octal | x hexadecimal )
charesc -> a | b | f | n | r | t | v | \ | " | ' | &
ascii -> ^cntrl | NUL | SOH | STX | ETX | EOT | ENQ | ACK
| BEL | BS | HT | LF | VT | FF | CR | SO | SI | DLE
| DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN
| EM | SUB | ESC | FS | GS | RS | US | SP | DEL
cntrl -> ascLarge | @ | [ | \ | ] | ^ | _
gap -> \ whitechar {whitechar}\

Перевод:
идентификатор-переменной -> (маленькая-буква {маленькая-буква | большая-буква | цифра | ' })<зарезервированный-идентификатор>
идентификатор-конструктора -> большая-буква {маленькая-буква | большая-буква | цифра | ' }
зарезервированный-идентификатор -> case | class | data | default | deriving | do | else
| if | import | in | infix | infixl | infixr | instance
| let | module | newtype | of | then | type | where | _
символ-переменной -> ( символ {символ | :})<зарезервированный-оператор| тире>
символ-конструктора -> (: {символ | :})< зарезервированный-оператор>
зарезервированный-оператор -> .. | : | :: | = | \ | | | <- | -> | @ | ~ | =>
идентификатор-переменной (переменные)
идентификатор-конструктора (конструкторы)
переменная-типа -> идентификатор-переменной (переменные типов)
конструктор-типа -> идентификатор-конструктора (конструкторы типов)
класс-типа -> идентификатор-конструктора (классы типов)
идентификатор-модуля -> идентификатор-конструктора (модули)
квалифицированный-идентификатор-переменной -> [ идентификатор-модуля . ] идентификатор-переменной
квалифицированный-идентификатор-конструктора -> [идентификатор-модуля . ] идентификатор-конструктора
квалифицированный-конструктор-типа -> [идентификатор-модуля . ] конструктор-типа
квалифицированный-класс-типа -> [идентификатор-модуля . ] класс-типа
квалифицированный-символ-переменной -> [идентификатор-модуля . ] символ-переменной
квалифицированный-символ-конструктора -> [идентификатор-модуля . ] символ-конструктора
десятичный-литерал -> цифра{цифра}
восьмиричный-литерал -> восьмиричная-цифра{восьмиричная-цифра}
шестнадцатиричный-литерал -> шестнадцатиричная-цифра{шестнадцатиричная-цифра}
целый-литерал -> десятичный-литерал
| 0o восьмиричный-литерал | 0O восьмиричный-литерал
| 0x шестнадцатиричный-литерал | 0X шестнадцатиричный-литерал
литерал-с-плавающей-точкой -> десятичный-литерал . десятичный-литерал [экспонента]
| десятичный-литерал экспонента
экспонента -> (e | E) [+ | -] десятичный-литерал
символьный-литерал -> ' (графический-символ<' | \> | пробел | эскейп-символ<\&>) '
строковый-литерал -> " {графический-символ<" | \> | пробел | эскейп-символ | разрыв}"
эскейп-символ -> \ ( символ-эскейп | символ-ascii | десятичный-литерал | o восьмиричный-литерал | x шестнадцатиричный-литерал )
символ-эскейп -> a | b | f | n | r | t | v | \ | " | ' | &
символ-ascii -> ^управляющий-символ | NUL | SOH | STX | ETX | EOT | ENQ | ACK
| BEL | BS | HT | LF | VT | FF | CR | SO | SI | DLE
| DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN
| EM | SUB | ESC | FS | GS | RS | US | SP | DEL
управляющий-символ -> большая-буква-ASCII | @ | [ | \ | ] | ^ | _
разрыв -> \ пробельный-символ {пробельный-символ}\

9.3  Размещение

В разделе 2.7 дается неформальное определение правила размещения. В этом разделе это правило определено более точно.

Смысл программы на Haskell может зависеть от размещения ее текста. Влияние размещения на ее смысл может быть полностью описано путем добавления фигурных скобок и точек с запятой в местах, определяемых размещением. Смысл такого дополнения программы состоит в том, чтобы сделать ее не зависимой от размещения текста.

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

"Отступом" лексемы является номер колонки для первого символа этой лексемы; отступом строки является отступ его крайней слева лексемы. Для того чтобы определить номер колонки, предположим, что используется шрифт фиксированной ширины со следующими условностями:

С целью соблюдения правил размещения, символы Unicode в исходной программе рассматриваются как те же символы фиксированной ширины, что и символы ASCII. Тем не менее, чтобы избежать визуальной путаницы, программистам следует избегать написания программ, в которых смысл неявного размещения зависит от ширины непробельных символов.

Применение

L токены []

передает не зависящую от размещения трансляцию токенов, где токены являются результатом лексического анализа модуля и добавления к нему указателей номеров колонок, как описано выше. Определение L заключается в следующем: где мы используем ":" в качестве оператора конструирования потока и "[]" для пустого потока.

L (<n>:ts) (m:ms) = ; : (L ts (m:ms)) если m = n
= } : (L (<n>:ts) ms) если n < m
L (<n>:ts) ms = L ts ms
L ({n}:ts) (m:ms) = { : (L ts (n:m:ms)) если n > m (Замечание 1)
L ({n}:ts) [] = { : (L ts [n]) если n > 0 (Замечание 1)
L ({n}:ts) ms = { : } : (L (<n>:ts) ms) (Замечание 2)
L (}:ts) (0:ms) = } : (L ts ms) (Замечание 3)
L (}:ts) ms = ошибка-разбора (Замечание 3)
L ({:ts) ms = { : (L ts (0:ms)) (Замечание 4)
L (t:ts) (m:ms) = } : (L (t:ts) ms) если m /= 0 и ошибка-разбора(t)
(Замечание 5)
L (t:ts) ms = t : (L ts ms)
L [] [] = []
L [] (m:ms) = } : L [] ms если m /=0 (Замечание 6)

Замечание 1.
Вложенный контекст должен иметь больший отступ, чем внешний контекст (n>m). Если нет --- L завершается с ошибкой, и компилятору следует указать на ошибку размещения. Пример:

  f x = let
           h y = let
    p z = z
                 in p
        in h

Здесь определение p имеет меньший отступ, чем отступ внешнего контекста, который устанавливается в этом случае путем определения h.

Замечание 2.
Если первый токен после where (скажем) не имеет отступа, большего чем внешний контекст размещения, то блок должен быть пуст, поэтому вставляются пустые фигурные скобки. Токен {n} заменяется на <n>, чтобы сымитировать ситуацию как если бы пустые фигурные скобки были явными.

Замечание 3.
Посредством сопоставления с 0 текущего контекста размещения, мы гарантируем, что явная закрывающая фигурная скобка может быть сопоставлена только явной открывающей фигурной скобке. Если явная закрывающая фигурная скобка будет сопоставлена неявной открывающей фигурной скобке --- возникнет ошибка разбора.

Замечание 4.
Это утверждение означает, что все пары фигурных скобок трактуются как явные контексты размещения, включая именованные создание типов данных и их обновление (раздел 3.15). В этом заключается разница между этой формулировкой и Haskell 1.4.

Замечание 5.
Дополнительное условие ошибка-разбора(t) интерпретируется следующим образом: если токены, порожденные до сих пор L вместе со следующим токеном t представляет недопустимый префикс в грамматике Haskell, а токены, порожденные к этому времени L, за которым следует токен "}", представляют правильный префикс в грамматике Haskell, то ошибка-разбора(t) равна истине.

Проверка m /= 0 контролирует, что неявно добавленная закрывающая фигурная скобка будет сопоставлена неявной открывающей фигурной скобке.

Замечание 6.
В конце ввода добавляются все незаконченные закрывающие фигурные скобки. Будет ошибкой оказаться здесь в пределах контекста без размещения (т.е. m = 0).

Если ни одно из данных выше правил не подойдет, то алгоритм завершится неудачей. Он может завершиться неудачей, например, когда будет достигнут конец ввода, и контекст без размещения будет активен, так как закрывающая фигурная скобка пропущена. Некоторые сбойные ситуации не обнаруживаются алгоритмом, хотя они могут быть: например, let }.

Замечание 1 реализует свойство, при котором обработка размещения может быть остановлена преждевременно из-за ошибки разбора. Например,

        let x = e; y = x in e'

правильно, потому что оно транслируется в

        let { x = e; y = x } in e'

Закрывающая фигурная скобка вставляется вследствие описанного выше правила ошибки разбора. Правило ошибки разбора трудно реализовать в его полной применимости ко всему, потому что выполнение этого влечет применение ассоциативностей. Например, выражение

  do a == b == c

имеет единственный однозначный (хотя, возможно, неправильный с точки зрения типов) разбор, а именно:

  (do { a == b }) == c

потому что (==) является неассоциативным. Поэтому программистам советуют избегать написания кода, который требует, чтобы синтаксический анализатор вставлял закрывающую фигурную скобку в таких ситуациях.

9.4  Грамотные комментарии

Соглашение о "грамотных комментариях", впервые разработанное Ричардом Бердом (Richard Bird) и Филиппом Уодлером (Philip Wadler) для Orwell, и позаимствованное в свою очередь Дональдом Кнутом (Donald Knuth) для "грамотного программирования", является альтернативным стилем программирования исходного кода на Haskell . Грамотный стиль поощряет комментарии, создавая их по умолчанию. Строка, в которой ">" является первым символом, интерпретируется как часть программы; все остальные строки являются комментарием.

Текст программы восстанавливается путем выбора только тех строк, которые начинаются с ">", и замены первого ">" на пробел. В полученном тексте размещение и комментарии применяются в точности как описано в главе 9.

Чтобы охватить некоторые случаи, где можно по ошибке пропустить ">", возникнет ошибка, если строка программы появится рядом с непробельной строкой комментария; строка рассматривается как пробельная, если она состоит только из пробельных символов.

Условно на стиль комментария указывает расширение файла: ".hs" указывает на обычный файл на Haskell, а ".lhs" указывает на файл с грамотным Haskell. С использованием этого стиля простая программа вычисления факториала могла бы выглядеть так:

   Эта грамотная программа запрашивает у пользователя число
   и выводит на экран факториал этого числа:

> main :: IO ()

> main = do putStr "Введите число: "
>           l <- readLine
>           putStr "n!= "
>           print (fact (read l))
          
  Это программа вычисления факториала.

> fact :: Integer -> Integer
> fact 0 = 1
> fact n = n * fact (n-1)

Альтернативный стиль грамотного программирования особенно подходит для использования вместе с системой обработки текста LaTeX. По этому соглашению только те части грамотной программы, которые полностью заключены между разделителями \begin{code}...\end{code}, рассматриваются как текст программы; все остальные строки --- комментарии. Более точно:

Нет необходимости вставлять дополнительные пустые строки до или после этих разделителей, хотя со стилистической точки зрения это может быть желательно. Например,

\documentstyle{article}

\begin{document}

\section{Introduction}

Это тривиальная программа, которая выводит первые 20 факториалов.

\begin{code}
main :: IO ()
main =  print [ (n, product [1..n]) | n <- [1..20]]
\end{code}

\end{document}

Этот стиль использует то же расширение файла. Нежелательно смешивать эти два стиля в одном файле.

9.5  Контекстно-свободный синтаксис

module -> module modid [exports] where body
| body
body -> { impdecls ; topdecls }
| { impdecls }
| { topdecls }
impdecls -> impdecl1 ; ... ; impdecln (n>=1)

Перевод:
модуль -> module идентификатор-модуля [список-экспорта] where тело
| тело
тело -> { список-объявлений-импорта ; список-объявлений-верхнего-уровня }
| { список-объявлений-импорта }
| { список-объявлений-верхнего-уровня }
список-объявлений-импорта -> объявление-импорта1 ; ... ; объявление-импортаn (n>=1)

exports -> ( export1 , ... , exportn [ , ] ) (n>=0)
export -> qvar
| qtycon [(..) | ( cname1 , ... , cnamen )] (n>=0)
| qtycls [(..) | ( qvar1 , ... , qvarn )] (n>=0)
| module modid

Перевод:
список-экспорта -> ( экспорт1 , ... , экспортn [ , ] ) (n>=0)
экспорт -> квалифицированная-переменная
| квалифицированный-конструктор-типа [(..) | ( c-имя1 , ... , c-имяn )] (n>=0)
| квалифицированный-класс-типа [(..) | ( квалифицированная-переменная1 , ... , квалифицированная-переменнаяn )] (n>=0)
| module идентификатор-модуля

impdecl -> import [qualified] modid [as modid] [impspec]
| (пустое объявление)
impspec -> ( import1 , ... , importn [ , ] ) (n>=0)
| hiding ( import1 , ... , importn [ , ] ) (n>=0)
import -> var
| tycon [ (..) | ( cname1 , ... , cnamen )] (n>=0)
| tycls [(..) | ( var1 , ... , varn )] (n>=0)
cname -> var | con

Перевод:
объявление-импорта -> import [qualified] идентификатор-модуля [as идентификатор-модуля] [спецификатор-импорта]
| (пустое объявление)
спецификатор-импорта -> ( импорт1 , ... , импортn [ , ] ) (n>=0)
| hiding ( импорт1 , ... , импортn [ , ] ) (n>=0)
импорт -> переменная
| конструктор-типа [ (..) | ( c-имя1 , ... , c-имяn )] (n>=0)
| класс-типа [(..) | ( переменная1 , ... , переменнаяn )] (n>=0)
c-имя -> переменная | конструктор

topdecls -> topdecl1 ; ... ; topdecln (n>=0)
topdecl -> type simpletype = type
| data [context =>] simpletype = constrs [deriving]
| newtype [context =>] simpletype = newconstr [deriving]
| class [scontext =>] tycls tyvar [where cdecls]
| instance [scontext =>] qtycls inst [where idecls]
| default (type1 , ... , typen) (n>=0)
| decl

Перевод:
список-объявлений-верхнего-уровня -> объявление-верхнего-уровня1 ; ... ; объявление-верхнего-уровняn (n>=1)
объявление-верхнего-уровня -> type простой-тип = тип
| data [контекст =>] простой-тип = список-конструкций [deriving-инструкция]
| newtype [контекст =>] простой-тип = новая-конструкция [deriving-инструкция]
| class [простой-контекст =>] класс-типа переменная-типа [where список-объявлений-классов]
| instance [простой-контекст =>] квалифицированный-класс-типа экземпляр [where список-объявлений-экземпляров]
| default (тип1 , ... , типn)   (n>=0)
| объявление

decls -> { decl1 ; ... ; decln } (n>=0)
decl -> gendecl
| (funlhs | pat0) rhs
cdecls -> { cdecl1 ; ... ; cdecln } (n>=0)
cdecl -> gendecl
| (funlhs | var) rhs
idecls -> { idecl1 ; ... ; idecln } (n>=0)
idecl -> (funlhs | var) rhs
| (empty)
gendecl -> vars :: [context =>] type (сигнатура типа)
| fixity [integer] ops (infix-объявление)
| (пустое объявление)
ops -> op1 , ... , opn (n>=1)
vars -> var1 , ..., varn (n>=1)
fixity -> infixl | infixr | infix

Перевод:
список-объявлений -> { объявление1 ; ... ; объявлениеn } (n>=0)
объявление -> общее-объявление
| (левая-часть-функции | образец0) правая-часть
список-объявлений-классов -> { объявление-класса1 ; ... ; объявление-классаn } (n>=0)
объявление-класса -> общее-объявление
| (левая-часть-функции | переменная) правая-часть
список-объявлений-экземпляров -> { объявление-экземпляра1 ; ... ; объявление-экземпляраn } (n>=0)
объявление-экземпляра -> (левая-часть-функции | переменная) правая-часть
| (пусто)
общее-объявление -> список-переменных :: [контекст =>] тип (сигнатура типа)
| ассоциативность [целый-литерал] список-операторов (infix-объявление)
| (пустое объявление)
список-операторов -> оператор1 , ... , операторn (n>=1)
список-переменных -> переменная1 , ... , переменнаяn (n>=1)
ассоциативность -> infixl | infixr | infix

type -> btype [-> type] (тип функции)
btype -> [btype] atype (наложение типов)
atype -> gtycon
| tyvar
| ( type1 , ... , typek ) (тип кортежа, k>=2)
| [ type ] (тип списка)
| ( type ) (конструктор в скобках)
gtycon -> qtycon
| () (тип объединения)
| [] (конструктор списка)
| (->) (конструктор функции)
| (,{,}) (конструкторы кортежей)
context -> class
| ( class1 , ... , classn ) (n>=0)
class -> qtycls tyvar
| qtycls ( tyvar atype1 ... atypen ) (n>=1)
scontext -> simpleclass
| ( simpleclass1 , ... , simpleclassn ) (n>=0)
simpleclass -> qtycls tyvar

Перевод:
тип -> b-тип [-> тип] (тип функции)
b-тип -> [b-тип] a-тип (наложение типов)
a-тип -> общий-конструктор-типа
| переменная-типа
| ( тип1 , ... , типk ) (тип кортежа, k>=2)
| [ тип ] (тип списка)
| ( тип ) (конструктор в скобках)
общий-конструктор-типа -> квалифицированный-конструктор-типа
| () (тип объединения)
| [] (конструктор списка)
| (->) (конструктор функции)
| (,{,}) (конструкторы кортежей)
контекст -> класс
| ( класс1 , ... , классn ) (n>=0)
класс -> квалифицированный-класс-типа переменная-типа
| квалифицированный-класс-типа ( переменная-типа a-тип1 ... a-типn ) (n>=1)
простой-контекст -> простой-класс
| ( простой-класс1 , ... , простой-классn ) (n>=0)
простой-класс -> квалифицированный-класс-типа переменная-типа

simpletype -> tycon tyvar1 ... tyvark (k>=0)
constrs -> constr1 | ... | constrn (n>=1)
constr -> con [!] atype1 ... [!] atypek (число аргументов конструктора con = k, k>=0)
| (btype | ! atype) conop (btype | ! atype) (инфиксный оператор conop)
| con { fielddecl1 , ... , fielddecln } (n>=0)
newconstr -> con atype
| con { var :: type }
fielddecl -> vars :: (type | ! atype)
deriving -> deriving (dclass | (dclass1, ... , dclassn)) (n>=0)
dclass -> qtycls

Перевод:
простой-тип -> конструктор-типа переменная-типа1 ... переменная-типаk (k>=0)
список-конструкций -> конструкция1 | ... | конструкцияn (n>=1)
конструкция -> конструктор [!] a-тип1 ... [!] a-типk (число аргументов конструктора con = k, k>=0)
| (b-тип | ! a-тип) оператор-конструктора (b-тип | ! a-тип) (инфиксный оператор conop)
| конструктор { объявление-поля1 , ... , объявление-поляn } (n>=0)
новая-конструкция -> конструктор a-тип
| конструктор { переменная :: тип }
объявление-поля -> список-переменных :: (тип | ! a-тип)
deriving-инструкция -> deriving (производный-класс | (производный-класс1, ... , производный-классn)) (n>=0)
производный-класс -> квалифицированный-класс-типа

inst -> gtycon
| ( gtycon tyvar1 ... tyvark ) (k>=0, все tyvar различны)
| ( tyvar1 , ... , tyvark ) (k>=2, все tyvar различны)
| [ tyvar ]
| ( tyvar1 -> tyvar2 ) (tyvar1 и tyvar2 различны)

Перевод:
экземпляр -> общий-конструктор-типа
| ( общий-конструктор-типа переменная-типа1 ... переменная-типаk ) (k>=0, все переменные-типа различны)
| ( переменная-типа1 , ... , переменная-типаk ) (k>=2, все переменные-типа различны)
| [ переменная-типа ]
| ( переменная-типа1 -> переменная-типа2 ) (переменная-типа1 и переменная-типа2 различны)

funlhs -> var apat {apat }
| pati+1 varop(a,i) pati+1
| lpati varop(l,i) pati+1
| pati+1 varop(r,i) rpati
| ( funlhs ) apat {apat }
rhs -> = exp [where decls]
| gdrhs [where decls]
gdrhs -> gd = exp [gdrhs]
gd -> | exp0

Перевод:
левая-часть-функции -> переменная такой-как-образец {такой-как-образец }
| образецi+1 оператор-переменной(a,i) образецi+1
| левый-образецi оператор-переменной(l,i) образецi+1
| образецi+1 оператор-переменной(r,i) правый-образецi
| ( левая-часть-функции ) такой-как-образец {такой-как-образец }
правая-часть -> = выражение [where список-объявлений]
| правая-часть-со-стражами [where список-объявлений]
правая-часть-со-стражами -> страж = выражение [правая-часть-со-стражами]
страж -> | выражение0

exp -> exp0 :: [context =>] type (сигнатура типа выражения)
| exp0
expi -> expi+1 [qop(n,i) expi+1]
| lexpi
| rexpi
lexpi -> (lexpi | expi+1) qop(l,i) expi+1
lexp6 -> - exp7
rexpi -> expi+1 qop(r,i) (rexpi | expi+1)
exp10 -> \ apat1 ... apatn -> exp (лямбда-абстракция, n>=1)
| let decls in exp (let-выражение)
| if exp then exp else exp (условное выражение)
| case exp of { alts } (case-выражение)
| do { stmts } (do-выражение)
| fexp
fexp -> [fexp] aexp (применение функции)

Перевод:
выражение -> выражение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-выражение)
| функциональное-выражение
функциональное-выражение -> [функциональное-выражение] выражение-аргумента (применение функции)

aexp -> qvar (переменная)
| gcon (общий конструктор)
| literal
| ( exp ) (выражение в скобках)
| ( exp1 , ... , expk ) (кортеж, k>=2)
| [ exp1 , ... , expk ] (список, k>=1)
| [ exp1 [, exp2] .. [exp3] ] (арифметическая последовательность)
| [ exp | qual1 , ... , qualn ] (описание списка, n>=1)
| ( expi+1 qop(a,i) ) (левое сечение)
| ( lexpi qop(l,i) ) (левое сечение)
| ( qop(a,i)<-> expi+1 ) (правое сечение)
| ( qop(r,i)<-> rexpi ) (правое сечение)
| qcon { fbind1 , ... , fbindn } (именованная конструкция, n>=0)
| aexp<qcon> { fbind1 , ... , fbindn } (именованное обновление, n >= 1)

Перевод:
выражение-аргумента -> квалифицированная-переменная (переменная)
| общий-конструктор (общий конструктор)
| литерал
| ( выражение ) (выражение в скобках)
| ( выражение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)

qual -> pat <- exp (генератор)
| let decls (локальное объявление)
| exp (страж)
alts -> alt1 ; ... ; altn (n>=1)
alt -> pat -> exp [where decls]
| pat gdpat [where decls]
| (пустая альтернатива)
gdpat -> gd -> exp [ gdpat ]
stmts -> stmt1 ... stmtn exp [;] (n>=0)
stmt -> exp ;
| pat <- exp ;
| let decls ;
| ; (пустая инструкция)
fbind -> qvar = exp

Перевод:
квалификатор -> образец <- выражение (генератор)
| let списки-объявлений (локальное объявление)
| выражение (страж)
список-альтернатив -> альтернатива1 ; ... ; альтернативаn (n>=1)
альтернатива -> образец -> выражение [where список-объявлений]
| образец образец-со-стражами [where список-объявлений]
| (пустая альтернатива)
образец-со-стражами -> страж -> выражение [ образец-со-стражами ]
список-инструкций -> инструкция1 ... инструкцияn выражение [;] (n>=0)
инструкция -> выражение ;
| образец <- выражение ;
| let список-объявлений ;
| ; (пустая инструкция)
связывание-имени-поля -> квалифицированная-переменная = выражение

pat -> var + integer (образец упорядочивания)
| pat0
pati -> pati+1 [qconop(n,i) pati+1]
| lpati
| rpati
lpati -> (lpati | pati+1) qconop(l,i) pati+1
lpat6 -> - (integer | float) (отрицательный литерал)
rpati -> pati+1 qconop(r,i) (rpati | pati+1)
pat10 -> apat
| gcon apat1 ... apatk (число аргументов конструктора gcon = k, k>=1)

Перевод:
образец -> переменная + целый-литерал (образец упорядочивания)
| образец0
образецi -> образецi+1 [квалифицированный-оператор-конструктора(n,i) образецi+1]
| левый-образецi
| правый-образецi
левый-образецi -> (левый-образецi | образецi+1) квалифицированный-оператор-конструктора(l,i) образецi+1
левый-образец6 -> - (целый-литерал | литерал-с-плавающей-точкой) (отрицательный литерал)
правый-образецi -> образецi+1 квалифицированный-оператор-конструктора(r,i) (правый-образецi | образецi+1)
образец10 -> такой-как-образец
| общий-конструктор такой-как-образец1 ... такой-как-образецk (число аргументов конструктора gcon = k, k>=1)

apat -> var [@ apat] ("такой как"-образец)
| gcon (число аргументов конструктора gcon = 0)
| qcon { fpat1 , ... , fpatk } (именованный образец, k>=0)
| literal
| _ (любые символы)
| ( pat ) (образец в скобках)
| ( pat1 , ... , patk ) (образец кортежа, k>=2)
| [ pat1 , ... , patk ] (образец списка, k>=1)
| ~ apat (неопровержимый образец)
fpat -> qvar = pat

Перевод:
такой-как-образец -> переменная [@ такой-как-образец] ("такой как"-образец)
| общий-конструктор (число аргументов конструктора gcon = 0)
| квалифицированный-конструктор { образец-с-именем1 , ... , образец-с-именемk } (именованный образец, k>=0)
| литерал
| _ (любые символы)
| ( образец ) (образец в скобках)
| ( образец1 , ... , образецk ) (образец кортежа, k>=2)
| [ образец1 , ... , образецk ] (образец списка, k>=1)
| ~ такой-как-образец (неопровержимый образец)
образец-с-именем -> квалифицированная-переменная = образец

gcon -> ()
| []
| (,{,})
| qcon
var -> varid | ( varsym ) (переменная)
qvar -> qvarid | ( qvarsym ) (квалифицированная переменная)
con -> conid | ( consym ) (конструктор)
qcon -> qconid | ( gconsym ) (квалифицированный конструктор)
varop -> varsym | `varid ` (оператор переменной)
qvarop -> qvarsym | `qvarid ` (квалифицированный оператор переменной)
conop -> consym | `conid ` (оператор конструктора)
qconop -> gconsym | `qconid ` (квалифицированный оператор конструктора)
op -> varop | conop (оператор)
qop -> qvarop | qconop (квалифицированный оператор)
gconsym -> : | qconsym

Перевод:
общий-конструктор -> ()
| []
| (,{,})
| квалифицированный-конструктор
переменная -> идентификатор-переменной | ( символ-переменной ) (переменная)
квалифицированная-переменная -> квалифицированный-идентификатор-переменной | ( квалифицированный-символ-переменной ) (квалифицированная переменная)
конструктор -> идентификатор-конструктора | ( символ-конструктора ) (конструктор)
квалифицированный-конструктор -> квалифицированный-идентификатор-конструктора | ( символ-общего-конструктора ) (квалифицированный конструктор)
оператор-переменной -> символ-переменной | `идентификатор-переменной ` (оператор переменной)
квалифицированный-оператор-переменной -> квалифицированный-символ-переменной | `квалифицированный-идентификатор-переменной ` (квалифицированный оператор переменной)
оператор-конструктора -> символ-конструктора | `идентификатор-конструктора ` (оператор конструктора)
квалифицированный-оператор-конструктора -> символ-общего-конструктора | `квалифицированный-идентификатор-конструктора ` (квалифицированный оператор конструктора)
оператор -> оператор-переменной | оператор-конструктора (оператор)
квалифицированный-оператор -> квалифицированный-оператор-переменной | квалифицированный-оператор-конструктора (квалифицированный оператор)
символ-общего-конструктора -> : | квалифицированный-символ-конструктора


Описание Haskell 98
наверх | назад | вперед | содержание | предметный указатель функций
Декабрь 2002