Сравнение людей на равенство
Рассмотрим такой тип данных:
>data Person = Person { firstName :: String
> , lastName :: String
> , age :: Int
> }
Тип описывает человека. Предположим, что среди людей не встречаются тёзки одного возраста. Если у нас есть два описания, можем ли мы выяснить, относятся ли они к одному и тому же человеку? Есть ли в такой операции смысл? Конечно, есть. Мы можем сравнить записи и проверить, равны они или нет. Вот почему имело бы смысл определить для нашего типа экземпляр класса >Eq
. Порождаем экземпляр:
>data Person = Person { firstName :: String
> , lastName :: String
> , age :: Int
> } deriving (Eq)
Когда мы определяем экземпляр класса >Eq
для типа и пытаемся сравнить два значения с помощью операторов >==
или >/=
, язык Haskell проверяет, совпадают ли конструкторы значений (хотя в нашем типе только один конструктор), а затем проверяет все данные внутри конструктора на равенство, сравнивая каждую пару полей с помощью оператора >==
. Таким образом, типы всех полей также должны иметь определённый экземпляр класса >Eq
. Так как типы полей нашего типа, >String
и >Int
, имеют экземпляры класса >Eq
, всё в порядке.
Запишем в файл несколько людей:
>mikeD = Person {firstName = "Майкл", lastName = "Даймонд", age = 45}
>adRock = Person {firstName = "Адам", lastName = "Горовиц", age = 45}
>mca = Person {firstName = "Адам", lastName = "Яух", age = 47}
И проверим экземпляр класса >Eq
:
>ghci> mca == adRock
>False
>ghci> mikeD == adRock
>False
>ghci> mikeD == mikeD
>True
>ghci> mca == Person {firstName = "Адам", lastName = "Яух", age = 47}
>True
Конечно же, так как теперь тип >Person
имеет экземпляр класса >Eq
, мы можем передавать его любым функциям, которые содержат ограничение на класс типа >Eq
в декларации, например функции >elem
.
>ghci> let beastieBoys = [mca, adRock, mikeD]
>ghci> mikeD `elem` beastieBoys
>True
Классы типов >Show
и >Read
предназначены для сущностей, которые могут быть преобразованы в строки и из строк соответственно. Как и для класса >Eq
, все типы в конструкторе типов также должны иметь экземпляры для классов >Show
и/или >Read
, если мы хотим получить такое поведение. Давайте сделаем наш тип данных >Person
частью классов >Show
и >Read
:
>data Person = Person { firstName :: String
> , lastName :: String