haskell-notes

пояснения, будьте уверены – в следующих главах мы обязательно обратимся к этим моментам и обсудим их

подробнее.

1.1 Общая картина

Программы на Haskell бывают двух видов: это приложения (executable) и библиотеки (library). Приложе-

ния представляют собой исполняемые файлы, которые решают некоторую задачу, к примеру – это может

быть компилятор языка, сортировщик данных в директориях, календарь, или цитатник на каждый день, лю-

бая полезная утилита. Библиотеки тоже решают задачи, но решают их внутри самого языка. Они содержат

отдельные значения, функции, которые можно подключать к другой программе Haskell, и которыми можно

пользоваться.

Программа состоит из модулей (module). И здесь работает правило: один модуль – один файл. Имя модуля

совпадает с именем файла. Имя модуля начинается с большой буквы, тогда как файлы имеют расширение

. hs. Например FirstModule. hs. Посмотрим на типичный модуль в Haskell:

—————————————

— шапка

module Имя(определение1, определение2,…, определениеN) where

import Модуль1()

import Модуль2()

—————————————

— определения

определение1

определение2

Каждый модуль содержит набор определений. Относительно модуля определения делятся на экспорти-

руемые и внутренние. Экспортируемые определения могут быть использованы за пределами модуля, а внут-

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

Модуль состоит из двух частей – шапки и определений.

Шапка В шапке после слова module объявляется имя модуля, за которым в скобках следует список экспорти-

руемых определений; после скобок стоит слово where. Затем идут импортируемые модули. С помощью

импорта модулей вы имеете возможность в данном модуле пользоваться определениями из другого

модуля.

Как после имени модуля, так и в директиве import скобки с определениями можно не писать,так как

в этом случае считается, что экспортируются/импортируются все определения.

| 13

Определения Эта часть содержит все определения модуля, при этом порядок следования определений не

имеет значения. То есть, не обязательно пользоваться в данной функции лишь теми значениями, что

были определены выше.

Модули взаимодействуют друг с другом с помощью экспортируемых определений. Один модуль может

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

import Модуль(определения). Модуль – это айсберг, на вершине которого – те функции, ради которых он

создавался (экспортируемые), а под водой – все служебные детали реализации (внутренние).

Итак, программа состоит из модулей, модули состоят из определений. Но что такое определения?

В Haskell определения могут описывать четыре вида сущностей:

• Типы.

• Значения.

• Классы типов.

• Экземпляры классов типов.

Теперь давайте рассмотрим их подробнее.

1.2 Типы

Типы представляют собой каркас программы. Они кратко описывают все возможные значения. Это очень

удобно. Опытный программист на Haskell может понять смысл функции по её названию и типу. Это не очень

сложно. Например, мы видим:

not :: Bool -> Bool

Выражение v :: T означает, что значение v имеет тип T. Стрелка a -> b означает функцию, то есть из a мы

можем получить b. Итак, перед нами функция из Bool в Bool, под названием not. Мы можем предположить,

что это логическая операция “не”. Или, перед нами такое определение типа:

reverse :: [a] -> [a]

Мы видим функцию с именем reverse, которая принимает список [a] и возвращает список [a], и мы

можем догадаться, что эта функция переворачивает список, то есть мы получаем список, у которого элементы

идут в обратном порядке. Маленькая буква a в [a] является параметром типа, на место параметра может быть

поставлен любой тип. Она говорит о том, что список содержит элементы типа a. Например, такая функция

соглашается переворачивать только списки логических значений:

reverseBool :: [Bool] -> [Bool]

Программа представляет собой описание некоторого явления или процесса. Типы определяют основные

слова или термины и способы их комбинирования. А значения представляют собой комбинации базовых

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

задаются типами.

Например, такое выражение определяет тип, в котором два базовых термина True или False

data Bool = True | False

Слово data ключевое, с него начинается любое определение нового типа. Символ | означает или. Наш

новый тип Bool является либо словом True, либо словом False. В этом типе есть только понятия, но нет

способов комбинирования, посмотрим на тип, в котором есть и то, и другое:

data [a] = [] | a : [a]

Это определение списка. Как мы уже поняли, a – это параметр. Список [a] может быть либо пустым

списком [], либо комбинацией a : [a]. В этой комбинации знак : объединяет элемент типа a и ещё один

список [a]. Это рекурсивное определение, они встречаются в Haskell очень часто. Если это пока кажется

непонятным, не пугайтесь, в следующих главах будет представлено много примеров с пояснениями.

Приведём ещё несколько примеров определений; ниже типы определяют базовые понятия для мира ка-

Страницы: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162