го моих пояснений, и вы поймёте, что к чему. Если что-то сразу не станет ясно, или где-то я опущу какие-то
пояснения, будьте уверены – в следующих главах мы обязательно обратимся к этим моментам и обсудим их
подробнее.
1.1 Общая картина
Программы на Haskell бывают двух видов: это
ния представляют собой исполняемые файлы, которые решают некоторую задачу, к примеру – это может
быть компилятор языка, сортировщик данных в директориях, календарь, или цитатник на каждый день, лю-
бая полезная утилита. Библиотеки тоже решают задачи, но решают их внутри самого языка. Они содержат
отдельные значения, функции, которые можно подключать к другой программе Haskell, и которыми можно
пользоваться.
Программа состоит из
совпадает с именем файла. Имя модуля начинается с большой буквы, тогда как файлы имеют расширение
. hs. Например FirstModule. hs. Посмотрим на типичный модуль в Haskell:
--------------------------------------
-- шапка
module Имя(определение1, определение2,..., определениеN) where
import Модуль1(... )
import Модуль2(... )
...
---------------------------------------
-- определения
определение1
определение2
...
Каждый модуль содержит набор определений. Относительно модуля определения делятся на
ренние – только внутри модуля, и обычно они служат для выражения экспортируемых определений.
Модуль состоит из двух частей – шапки и определений.
руемых определений; после скобок стоит слово 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]