Класс Read
в чём-то является обратным классом типов для класса Show
. Класс Show
служит для преобразования значений нашего типа в строку, класс Read
нужен для преобразования строк в значения типа. Запомните, что при использовании функции чтения мы должны явно аннотировать тип возвращаемого значения. Если не указать тип результата явно, язык Haskell не сможет угадать, какой тип мы желали бы получить. Чтобы это проиллюстрировать, поместим в файл строку, представляющую некоторого человека, а затем загрузим файл в GHCi:
mysteryDude = "Person { firstName =\"Майкл\"" ++
", lastName =\"Даймонд\"" ++
", age = 45}"
Для большей «читабельности» мы разбили строку на несколько фрагментов. Если теперь необходимо вызвать с этой строкой функцию read
, то потребуется указать тип, который мы ожидаем получить:
ghci> read mysteryDude :: Person
Person {firstName = "Майкл", lastName = "Даймонд", age = 45}
Если далее в программе мы используем результат чтения таким образом, что язык Haskell сможет вывести его тип, мы не обязаны использовать аннотацию типа.
ghci> read mysteryDude == mikeD
True
Так же можно считывать и параметризованные типы, но при этом следует явно указывать все типы-параметры.
Если мы попробуем сделать так:
ghci> read "Just 3" :: Maybe a
то получим сообщение об ошибке: Haskell не в состоянии определить конкретный тип, который следует подставить на место типовой переменной a
. Если же мы точно укажем, что хотим получить Int
, то всё будет прекрасно:
ghci> read "Just 3" :: Maybe Int
Just 3
Порядок в суде!
Класс типов Ord
, предназначенный для типов, значения которых могут быть упорядочены, также допускает автоматическое порождение экземпляров. Если сравниваются два значения одного типа, сконструированные с помощью различных конструкторов данных, то меньшим считается значение, конструктор которого определён раньше. Рассмотрим, к примеру, тип Bool
, значениями которого могут быть False
или True
. Для наших целей удобно предположить, что он определён следующим образом:
data Bool = False | True deriving (Ord)
Поскольку конструктор False
указан первым, а конструктор True
– после него, мы можем считать, что True
больше, чем False
.
ghci> True `compare` False
GT
ghci> True > False
True
ghci> True < False
False
Если два значения имеют одинаковый конструктор, то при отсутствии полей они считаются равными. Если поля есть, то выполняется их сравнение. Заметьте, что в этом случае типы полей должны быть частью класса типов Ord
.
В типе данных Maybe
a
конструктор значений Nothing
указан раньше Just
– это значит, что значение Nothing
всегда меньше, чем Just <
, даже если это «нечто» равно минус одному миллиону триллионов. Но если мы сравниваем два значения Just
, после сравнения конструкторов начинают сравниваться поля внутри них.
ghci> Nothing < Just 100
True
ghci> Nothing > Just (–49999)
False
ghci> Just 3 `compare` Just 2
GT
ghci>Just 100 > Just 50
True
Но сделать что-нибудь вроде Just (*3) > Just (*2)
не получится, потому что (*3)
и (*2)
– это функции, а они не имеют экземпляров для класса Ord
.
Любой день недели
Мы легко можем использовать алгебраические типы данных для того, чтобы создавать перечисления, и классы типов Enum
и Bounded
помогают нам в этом. Рассмотрим следующий тип:
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
Так как все конструкторы значений нульарные (не принимают параметров, то есть не имеют полей), допустимо сделать для нашего типа экземпляр класса Enum
. Класс типов Enum
предназначен для типов, для значений которых можно определить предшествующие и последующие элементы. Также мы можем определить для него экземпляр класса Bounded
– он предназначен для типов, у которых есть минимальное и максимальное значения. Ну и уж заодно давайте сделаем для него экземпляры всех остальных классов типов, которые можно сгенерировать автоматически, и посмотрим, что это даст.
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
deriving (Eq, Ord, Show, Read, Bounded, Enum)
Так как для нашего типа автоматически сгенерированы экземпляры классов Show
и Read
, можно конвертировать значения типа в строки и из строк:
ghci> Wednesday
Wednesday