52700.fb2
Тип-обёртка newtype
Ключевое слово newtype вводит новый тип-обёртку. Тип-обёртка может иметь только один конструктор,
у которого лишь одни аргумент. Запись:
newtype Sum a = Sum a
Это тоже самое, что и
data Sum a = Sum a
Единственное отличие заключается в том, что в случае newtype вычислитель не видит разницы между
Sum a и a. Её видит лишь компилятор. Это означает, что на разворачивание и заворачивание такого значения
в тип обёртку не тратится никаких усилий. Такие типы подходят для решения двух задач:
• Более точная проверка типов.
Например у нас есть типы, которые описывают физические величины, все они являются числами, но у
них также есть и размерности. Мы можем написать:
type Velocity
= Double
type Time
= Double
type Length
= Double
velocity :: Length -> Time -> Velocity
velocity leng time = leng / time
Накопление результата | 113
В этом случае мы спокойно можем подставить на место времени путь и наоборот. Но с помощью типов
обёрток мы можем исключить эти случаи:
newtype Velocity
= Velocity
Double
newtype Time
= Time
Double
newtype Length
= Length
Double
velocity :: Length -> Time -> Velocity
velocity (Length leng) (Time time) = Velocity $ leng / time
В этом случае мы проводим проверку по размерностям, компилятор не допустит смешивания данных.
• Определение нескольких экземпляров одного класса для одного типа. Этот случай мы как раз и рас-
сматриваем для класса Monoid. Нам нужно сделать два экземпляра для одного и того же типа Num a
=> a.
Сделаем две обёртки!
newtype Sum
a = Sum
a
newtype Prod a = Prod a
Тогда мы можем определить два экземпляра для двух разных типов:
Один для Sum:
instance Num a => Monoid (Sum a) where
mempty
= Sum 0
mappend (Sum a) (Sum b) = Sum (a + b)