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

с такого:

>data Car = Car { company :: String

>               , model :: String

>               , year :: Int

>               } deriving (Show)

на такой:

>data Car a b c = Car { company :: a

>                     , model :: b

>                     , year :: c

>                     } deriving (Show)

Но выиграем ли мы в чём-нибудь? Ответ – вероятно, нет, потому что впоследствии мы всё равно определим функции, которые работают с типом >Car String String Int. Например, используя первое определение >Car, мы могли бы создать функцию, которая отображает свойства автомобиля в виде понятного текста:

>tellCar :: Car –> String

>tellCar (Car {company = c, model = m, year = y}) =

>  "Автомобиль " ++ c ++ " " ++ m ++ ", год: " ++ show y


>ghci> let stang = Car {company="Форд", model="Мустанг", year=1967}

>ghci> tellCar stang

>"Автомобиль Форд Мустанг, год: 1967"

Приятная маленькая функция. Декларация типа функции красива и понятна. А что если >Car – это >Car a b c?

>tellCar :: (Show a) => Car String String a –> String

>tellCar (Car {company = c, model = m, year = y}) =

>  "Автомобиль " ++ c ++ " " ++ m ++ ", год: " ++ show y

Мы вынуждены заставить функцию принимать параметр >Car типа >(Show a) => Car String String a. Как видите, декларация типа функции более сложна; единственное преимущество, которое здесь имеется, – мы можем использовать любой тип, имеющий экземпляр класса >Show, как тип для типовой переменной >c.

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

>"Автомобиль Форд Мустанг, год: 1967"

>ghci> tellCar (Car "Форд" "Мустанг" "тысяча девятьсот шестьдесят седьмой")

>"Автомобиль Форд Мустанг, год: \"тысяча девятьсот шестьдесят седьмой\""

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

>Car "Форд" "Мустанг" 1967 :: (Num t) => Car [Char] [Char] t

>ghci> :t Car "Форд" "Мустанг" "тысяча девятьсот шестьдесят седьмой"

>Car "Форд" "Мустанг" "тысяча девятьсот шестьдесят седьмой"

>  :: Car [Char] [Char] [Char]

На практике мы всё равно в большинстве случаев использовали бы >Car String String Int, так что в параметризации типа >Car большого смысла нет. Обычно мы параметризируем типы, когда для работы нашего типа неважно, что в нём хранится. Список элементов – это просто список элементов, и неважно, какого они типа: список работает вне зависимости от этого. Если мы хотим суммировать список чисел, то в суммирующей функции можем уточнить, что нам нужен именно список чисел. То же самое верно и для типа >Maybe. Он предоставляет возможность не иметь никакого значения или иметь какое-то одно значение. Тип хранимого значения не важен.

Ещё один известный нам пример параметризованного типа – отображения