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

Объявления и связывания имен

Аннотация: В этой лекции мы опишем синтаксис и неформальную семантику объявлений Haskell

module \to module modid [exports] where body
| body
body \to { impdecls ; topdecls }
| { impdecls }
| { topdecls }
topdecls \to topdecl1 ; ... ; topdecln (n >= 1)
topdecl \to 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
decls \to { decl1 ; ... ; decln } (n >= 0)
decl \to gendecl
| (funlhs | pat0) rhs
cdecls \to { cdecl1 ; ... ; cdecln } (n >= 0)
cdecl \to gendecl
| (funlhs | var) rhs
idecls \to { idecl1 ; ... ; idecln } (n >= 0)
idecl \to (funlhs | var) rhs (пусто)
| gendecl
\to vars :: [context =>] type (сигнатура типа)
| fixity [integer] ops (infix-объявление)
| (пустое объявление)
ops \to op1 , ... , opn (n >= 1)
vars \to var1 , ... , varn (n >= 1)
fixity \to infixl | infixr | infix

Перевод:

модуль \to module идентификатор-модуля [список-экспорта] where тело
| тело
тело \to { список-объявлений-импорта ; список-объявлений-верхнего-уровня }
| { список-объявлений-импорта }
| { список-объявлений-верхнего-уровня }
список-объявлений-верхнего-уровня \to объявление-верхнего-уровня1 ; ... ; объявление-верхнего-уровняn (n >= 1)
объявление-верхнего-уровня \to type простой-тип = тип
| data [контекст \Rightarrow ] простой-тип = список-конструкций [deriving-инструкция]
| newtype [контекст \Rightarrow ] простой-тип = новая-конструкция [deriving-инструкция]
| class [простой-контекст \Rightarrow ] класс-типа переменная-типа [where список-объявлений-классов]
| instance [простой-контекст \Rightarrow ] квалифицированный-класс-типа экземпляр [where список-объявлений-экземпляров]
| default (тип1 , ... , типn) (n >= 0)
| объявление
список-объявлений \to { объявление1 ; ... ; объявлениеn } (n >= 0)
объявление \to общее-объявление
| (левая-часть-функции | образец0) правая-часть
список-объявлений-классов \to { объявление-класса1 ; ... ; объявление-классаn } (n >= 0)
объявление-класса \to общее-объявление
| (левая-часть-функции | переменная) правая-часть
список-объявлений-экземпляров \to { объявление-экземпляра1 ; ... ; объявление-экземпляраn } (n >= 0)
объявление-экземпляра \to (левая-часть-функции | переменная) правая-часть
| (пусто)
общее-объявление \to список-переменных :: [контекст \Rightarrow ] тип (сигнатура типа)
| ассоциативность [целый-литерал] список-операторов (infix-объявление)
| (пустое объявление)
список-операторов \to оператор1 , ... , операторn (n >= 1)
список-переменных \to переменная1 , ... , переменнаяn (n >= 1)
ассоциативность \to infixl | infixr | infix

Объявления в синтаксической категории topdecls (список-объявлений-верхнего-уровня) допустимы только на верхнем уровне модуля Haskell (см. лекцию "Модули" ), тогда как decls (список-объявлений) можно использовать или на верхнем уровне, или во вложенных областях видимости (т.е. в пределах конструкций let или where ).

Для описания мы разделили объявления на три группы: группу определяемых пользователем типов данных, состоящую из объявлений type, newtype и data (раздел "Объявления и связывания имен" ), группу классов типов и перегрузок операторов, состоящую из объявлений class, instance и default (раздел "Объявления и связывания имен" ), и группу вложенных объявлений, состоящую из связываний значений, сигнатур типов и infix-объявлений (раздел "Объявления и связывания имен" ).

В Haskell есть несколько примитивных типов данных, которые являются "зашитыми" (такие как целые числа и числа с плавающей точкой), но большинство "встроенных" типов данных определено с помощью обычного кода на Haskell с использованием обычных объявлений type и data. Эти "встроенные" типы данных подробно описаны в разделе "Предопределенные типы и классы" .

4.1 Обзор типов и классов

Haskell использует традиционную систему полиморфных типов Хиндли-Милнера (Hindley-Milner) для того, чтобы обеспечить статическую семантику типов [3, 5], но система типов была расширена с помощью классов типов (или просто классов), которые обеспечивают структурированный способ ввести перегруженные функции.

Объявление class (раздел "Объявления и связывания имен" ) вводит новый класс типа и перегруженные операции, которые должны поддерживаться любым типом, который является экземпляром этого класса. Объявление instance (раздел "Объявления и связывания имен" ) объявляет, что тип является экземпляром класса и включает определения перегруженных операций, называемых методами класса, инстанцированных на названном типе.

Например, предположим, что мы хотим перегрузить операции (+) и negate на типах Int и Float. Мы вводим новый класс типов, названный Num:

class Num a  where          - упрощенное объявление класса Num
    (+)    :: a -> a -> a     - (Класс Num определен в Prelude)
    negate :: a -> a

Это объявление можно толковать так: "тип a является экземпляром класса Num, если есть методы класса (+) и negate заданных типов, определенные на этом типе."

Затем мы можем объявить Int и Float экземплярами этого класса:

instance Num Int  where     - упрощенный экземпляр Num Int
    x + y       =  addInt x y
    negate x    =  negateInt x
  
  instance Num Float  where   - упрощенный экземпляр Num Float
    x + y       =  addFloat x y
    negate x    =  negateFloat x

где предполагается, что addInt, negateInt, addFloat и negateFloat - примитивные, в данном случае, функции, но вообще могут быть любыми определяемыми пользователем функциями. Первое сверху объявление можно толковать так: " Int является экземпляром класса Num в соответствии с этими определениями (т.е. методами класса) для (+) и negate."

Большее количество примеров классов типов можно найти в работах Джонса (Jones) [7] или Уодлера и Блотта (Wadler и Blott) [12]. Термин "класс типа" использовался для описания системы типов в исходном языке Haskell 1.0, а термин "конструктор класса" - для описания расширения исходных классов типов. Больше нет никакой причины использовать два различных термина: в этом описании "класс типа" включает и классы типов исходного языка Haskell , и конструируемые классы, введенные Джонсом (Jones).