Опубликован: 19.09.2008 | Доступ: свободный | Студентов: 658 / 70 | Оценка: 4.50 / 5.00 | Длительность: 21:25:00
Лекция 4:

Выражения

3.1 Ошибки

Ошибки во время вычисления выражений, обозначаемые как _|_, в программе на Haskell не отличимы от незавершенного вычисления. Поскольку Haskell является языком с нестрогой типизацией данных, все типы Haskell включают _|_. Другими словами, значение любого типа может быть связано с вычислением, которое будет завершено, когда потребуется результат вычисления, и завершится с ошибкой. При своем вычислении ошибки вызывают немедленное завершение программы и не могут быть отловлены пользователем. Prelude содержит две функции, которые сразу вызывают такие ошибки:

error     :: String -> a
undefined :: a

Вызов функции error завершает выполнение программы и возвращает в операционную систему соответствующий признак ошибки. Он также должен вывести на экран строку некоторым, зависящим от системы, способом. Когда используется функция undefined, сообщение об ошибке создается компилятором.

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

3.2 Переменные, конструкторы, операторы и литералы

aexp -> qvar (переменная)
| gcon
| literal (общий конструктор)
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 используется специальный синтаксис. Оператор - это функция, которая может быть применена, используя инфиксный синтаксис (раздел "3.4" ), или частично применена, используя сечения (раздел " 3.5" ).

Оператор представляет собой символ оператора, например, + или $$, или обычный идентификатор, заключенный в обратные кавычки, например, 'op'. Вместо префиксной записи op x y можно использовать инфиксную запись x 'op' y. Если ассоциативность и приоритет для 'op' не заданы, то по умолчанию используется наивысший приоритет и левоассоциативность (см. раздел "4.4.2" ).

Наоборот, символ оператора может быть преобразован в обычный идентификатор, если записать его в круглых скобках. Например, (+) x y эквивалентно x + y, а foldr (*) 1 xs эквивалентно foldr (\x y -> x*y) 1 xs.

Для обозначения некоторых конструкторов встроенных типов используется специальный синтаксис, как это видно из грамматики для gcon (общего-конструктора) и literal (литерала). Они описаны в разделе " 6.1."

Целый литерал представляет собой применение функции fromInteger к соответствующему значению типа Integer. Аналогично, литерал с плавающей точкой обозначает применение функции fromRational к значению типа Rational (то есть Ratio Integer ).

Трансляция:

Целый литерал i эквивалентен fromInteger i, где fromInteger - метод класса Num (см. раздел " 6.4.1" ).

Литерал с плавающей точкой f эквивалентен fromRational (n Ratio.% d), где fromRational - метод класса Fractional, а Ratio.% составляет из двух целых чисел рациональное число в соответствии с определением, заданным в библиотеке Ratio. Если заданы целые числа n и d, то n/d = f.

3.3 Производные функции и лямбда-абстракции

fexp -> [fexp] aexp (применение функции)
exp -> \ apat_1 ...; apat_n -> exp (лямбда-абстракция, n >=1 )

Перевод:

функциональное-выражение ->    [функциональное-выражение] выражение-аргумента (применение функции)
выражение -> \ такой-как-образец1 ... такой-как-образецn -> выражение (лямбда-абстракция, n >= 1 )

Применение функции записывается в виде e1 e2. Применение левоассоциативно, поэтому в (f x) y скобки можно опустить. Поскольку e1 может являться конструктором данных, возможно частичное применение конструкторов данных.

Лямбда-абстракции записываются в виде \ p1 ... pn -> e, где pi - образцы. Выражение вида \x:xs -> x синтаксически неправильно, его можно правильно записать в виде \(x:xs) -> ;x.

Набор образцов должен быть линейным: ни одна переменная не должна появляться в наборе более одного раза.

Трансляция:

Выполняются следующие тождества:

\ p1 ... pn -> e=\ x1 ... xn -> case (x1, ... , xn) of (p1, ..., pn) -> e

где xi - новые идентификаторы.

Используя эту трансляцию в комбинации с с семантикой case-выражений и сопоставлений с образцом, описанной в разделе "3.17.3" , получим: если сопоставление с образцом завершится неудачно, то результатом будет _|_.