Изучай Haskell во имя добра! (Липовача) - страница 84

>firstName :: Person –> String

>firstName (Person firstname _ _ _ _ _) = firstname


>lastName :: Person –> String

>lastName (Person _ lastname _ _ _ _) = lastname


>age :: Person –> Int

>age (Person _ _ age _ _ _) = age


>height :: Person –> Float

>height (Person _ _ _ height _ _) = height


>phoneNumber :: Person –> String

>phoneNumber (Person _ _ _ _ number _) = number


>flavor :: Person –> String

>flavor (Person _ _ _ _ _ flavor) = flavor

Фу-ух! Мало радости писать такие функции!.. Этот метод очень громоздкий и скучный, но он работает.

>ghci> let guy = Person "Фредди" "Крюгер" 43 184.2 "526–2928" "Эскимо"

>ghci> firstName guy

>"Фредди"

>ghci> height guy

>184.2

>ghci> flavor guy

>"Эскимо"

Вы скажете – должен быть лучший способ! Ан нет, извиняйте, нету… Шучу, конечно же. Такой метод есть! «Ха-ха» два раза. Создатели языка Haskell предусмотрели подобную возможность – предоставили ещё один способ для записи типов данных. Вот как мы можем достигнуть той же функциональности с помощью синтаксиса записей с именованными полями:

>data Person = Person { firstName :: String

>                     , lastName :: String

>                     , age :: Int

>                     , height :: Float

>                     , phoneNumber :: String

>                     , flavor :: String } deriving (Show)

Вместо того чтобы просто перечислять типы полей через запятую, мы используем фигурные скобки. Вначале пишем имя поля, например >firstName, затем ставим два двоеточия >:: и, наконец, указываем тип. Результирующий тип данных в точности такой же. Главная выгода – такой синтаксис генерирует функции для извлечения полей. Язык Haskell автоматически создаст функции >firstName, >lastName, >age, >height, >phoneNumber и >flavor.

>ghci> :t flavor

>flavor :: Person –> String

>ghci> :t firstName

>firstName :: Person –> String

Есть ещё одно преимущество в использовании синтаксиса записей. Когда мы автоматически генерируем экземпляр класса >Show для типа, он отображает тип не так, как если бы мы использовали синтаксис записей с именованными полями для объявления и инстанцирования типа. Например, у нас есть тип, представляющий автомобиль. Мы хотим хранить следующую информацию: компания-производитель, название модели и год производства.

>data Car = Car String String Int deriving (Show)

Автомобиль отображается так:

>ghci> Car "Форд" "Мустанг" 1967

>Car "Форд" "Мустанг" 1967

Используя синтаксис записей с именованными полями, мы можем описать новый автомобиль так:

>data Car = Car { company :: String

>               , model :: String

>               , year :: Int

>               } deriving (Show)