цию на пробелы. Зачем это нужно? Дело в том, что в разных редакторах на табуляцию может быть назначено
разное количество пробелов, так код набранный с двухзначной табуляцией будет очень трудно прочитать
если открыть его в редакторе с четырьмя пробелами вместо табуляции. Поскольку очень часто табуляция
перемежается с пробелами и выравнивание может “поехать”. Поэтому признаком хорошего стиля в Haskell
считается полный отказ от табуляции.
1.8 Краткое содержание
Итак подведём итоги: у нас есть две операции для определения типов (сумма и произведение) и по одной
для значений (синонимы), классов типов и экземпляров. А также бесконечное множество их комбинаций, из
которых и состоит увлекательный мир Haskell. Конечно не только из них, есть нюансы, синтаксический сахар,
расширения языка. Об этом и многом другом мы узнаем из этой книги.
Интересно, что в Haskell, несмотря на обилие конструкций и библиотек, ты чувствуешь, что за ними стоит
нечто из мира науки, мира чистого знания. Ты не просто учишься пользоваться определёнными функциями
или классами, а узнаёшь что-то новое и красивое.
1.9 Упражнения
Потренируйтесь в описаниях в рамках системы типов. Вы определяете базовые понятия и способы их
комбинирования. У вас есть три операции:
• Сумма типов data T = A1 | A2. Перечисление альтернатив
• Произведение типов data T = S S1 S2. Этим мы говорим, что понятие состоит из нескольких.
• Взятие в список [T]. Обозначает множественное число, элементов типа T их может быть несколько.
Опишите что-либо: комнату, дорогу, город, человека, главу из книги, математическую теорию, всё что
угодно.
Ниже приведён пример для понятий из этой главы:
data Program = Programm ProgramType [Module]
data ProgramType = Executable | Library
data Module = Module [Definition]
data Definition = Definition DefinitionType Element
data DefinitionType = Export | Inner
data Element = ET Type | EV Value | EC Class | EI Instance
data Type
= Type String
data Value
= Value String
data Class
= Class String
data Instance = Instance String
После того как вы закончите с описанием, подумайте, какие производные связи могли бы вас заинтере-
совать. Какие функции вам бы хотелось определить в этом описании. Выпишите их типы без определений,
например так:
— Все объявления типов в модуле
getTypes :: Module -> [Type]
— Провести редукцию значения:
reduce :: Value -> Program -> Value
— Проверить типы:
Краткое содержание | 23
checkTypes :: Program -> Bool
— Заменить все определения в модуле на новые
setDefinitions
:: Module -> [Definition] -> Module
— Упорядочить определения по какому-лбо принципу
orderDefinitions :: [Definition] -> [Definition]
Подумайте: если у вас есть все эти функции, какие производные значения могли бы вам сказать что-
нибудь интересное.
24 | Глава 1: Основы
Глава 2
Первая программа
Я вот говорю-говорю, а вдруг я вас обманываю, и ничего этого нет. В этой главе мы перейдём к програм-
мированию и запустим нашу первую программу в Haskell. Будет много примеров, на которых мы закрепим
наши знания.
2.1 Интерпретатор
Для запуска кода мы будем пользоваться приложением GHC (Glorious Glasgow Haskell Compiler) наиболее
развитой системой интерпретации Haskell программ. В GHC есть компилятор ghc и интерпретатор ghci. Пока
мы будем пользоваться лишь интерпретатором. Если вы не знаете как установить ghc загляните в приложе-
ние. Также нам понадобится текстовый редактор с подсветкой синтаксиса. Подсветка синтаксиса для Haskell
по умолчанию есть в редакторах Vim, Emacs, gedit, geany, yi. Есть IDE для Haskell Leksah. Мы будем писать
модули в файлах и загружать их в интерпретатор. Если вы не знаете продвинутых текстовых редакторов
вроде Vim или Emacs, лучше всего будет начать с gedit.
Интерпретатор позволяет загружать модуль с определениями и набирать значения в командной строке.
Мы набираем значение, а интерпретатор редуцирует его и показывает нам ответ. Интерпретатор запускается
командой ghci в терминале. Определения из модуля могут быть загружены в интерпретатор двумя способа-
ми, либо при запуске интерпретатора командой ghci ИмяМодуля. hs либо в самом интерпретаторе командой
:l ИмяМодуля. hs.
Рассмотрим некоторые полезные команды интерпретатора:
Выводит на экран список доступных команд
:t Expression Возвращает тип выражения.
:set +t После выполнения команды интерпретатор будет выводить на экран не только результат вычисле-
ния выражения, но и его тип.
:set +s После выполнения команды интерпретатор будет выводить на экран не только результат вычисле-
ния выражения, но и статистику вычислений.
:l ИмяМодуля Загружает модуль в интерпретатор.
:cd Директория Перейти в данную директорию.
:r Перезагружает, последний загруженный модуль. Этой командой можно пользоваться после внесения в
модуль изменений.
:q Выход из интерпретатора.
2.2 У-вей
Согласно даосам основной принцип жизни заключается в недеянии (у-вей). Всё происходит естественно и
словно само собой. Давайте создадим модуль который ничего не делает. Создадим пустой модуль и загрузим
его в интерпретатор.
module Empty where
import Prelude()
| 25
Зачем мы написали import Prelude()? Этой фразой мы говорим, что не хотим ничего импортировать
из модуля Prelude. По умолчанию в любой модуль загружается модуль Prelude, который содержит много
полезных определений. К примеру там определяется тип Bool, списки и функции для них, символы, классы
типов для сравнения на равенство и печати значений и много, много других определений. В первых главах
я хочу сделать акцент на самом языке Haskell, а не на производных выражениях, поэтому пока мы будем в
явном виде загружать из модуля Prelude лишь самые необходимые определения.
Сохраним модуль в файле Empty. hs, сделаем директорию модуля текущей и запустим интерпретатор
командой ghci Empty (имя расширения можно не писать). Также можно просто запустить интерпретатор
командой ghci, переключиться на директорию командой :cd и загрузить модуль командой :l Empty.
$ ghci
GHCi, version 7.4.1: http://www.haskell.org/ghc/
for help
Loading package ghc-prim … linking … done.
Loading package integer-gmp … linking … done.
Loading package base … linking … done.
Prelude> :cd ~/haskell-notes/code/ch-2/
Prelude> :l Empty.hs
[1 of 1] Compiling Empty
( Empty.hs, interpreted )
Ok, modules loaded: Empty.
*Empty>
Слева от знака приглашения к вводу > отображаются загруженные в интерпретатор модули. По умол-
чанию загружается модуль Prelude. После выполнения команды :l мы видим, что Prelude сменилось на
Empty.
Теперь давайте потренируемся перезагружать модули. Давайте изменим наш модуль, сделаем его не та-
ким пустым, убрав последние две скобки от модуля Prelude в директиве import. Теперь сохраним изменения
и выполним команду :r.
*Empty> :r
[1 of 1] Compiling Empty
( Empty. hs, interpreted )
Ok, modules loaded: Empty.
*Empty>
Завершим сессию интерпретатора командой :q.
*Empty> :q
Leaving GHCi.
Внешние модули должны находится в текущей директории. Давайте потренируемся с подключением
определений из внешних модулей. Создадим модуль близнец модуля Empty. hs:
module EmptyEmpty where
import Prelude()
И сохраним его в той же директории, что и модуль Empty, теперь мы можем включить все определения





