Пока что вы научились создавать свои алгебраические типы данных, используя ключевое слово >data
. Вы также увидели, как можно давать синонимы имеющимся типам с применением ключевого слова >type
. В этом разделе мы рассмотрим, как создаются новые типы на основе имеющихся типов данных с использованием ключевого слова >newtype
. И в первую очередь, конечно, поговорим о том, чем всё это может быть нам полезно.
В главе 11 мы обсудили пару способов, при помощи которых списковый тип может быть аппликативным функтором. Один из этих способов состоит в том, чтобы заставить оператор ><*>
брать каждую функцию из списка, являющегося его левым параметром, и применять её к каждому значению в списке, который находится справа, что в результате возвращает все возможные комбинации применения функции из левого списка к значению в правом:
>ghci> [(+1),(*100),(*5)] <*> [1,2,3]
>[2,3,4,100,200,300,5,10,15]
Второй способ заключается в том, чтобы взять первую функцию из списка слева от оператора ><*>
и применить её к первому значению справа, затем взять вторую функцию из списка слева и применить её ко второму значению справа, и т. д. В конечном счёте получается нечто вроде застёгивания двух списков.
Но списки уже имеют экземпляр класса >Applicative
, поэтому как нам определить для списков второй экземпляр класса >Applicative
? Как вы узнали, для этой цели был введён тип >ZipList a
. Он имеет один конструктор данных >ZipList
, у которого только одно поле. Мы помещаем оборачиваемый нами список в это поле. Далее для типа >ZipList
определяется экземпляр класса >Applicative
, чтобы, когда нам понадобится использовать списки в качестве аппликативных функторов для застёгивания, мы могли просто обернуть их с по мощью конструктора >ZipList
. Как только мы закончили, разворачиваем их с помощью >getZipList
:
>ghci> getZipList $ ZipList [(+1),(*100),(*5)] <*> ZipList [1,2,3]
>[2,200,15]
Итак, какое отношение это имеет к ключевому слову >newtype
? Хорошо, подумайте, как бы мы могли написать объявление >data
для нашего типа >ZipList a
! Вот один из способов:
>data ZipList a = ZipList [a]
Это тип, который обладает лишь одним конструктором данных, и этот конструктор данных имеет только одно поле, которое является списком сущностей. Мы также могли бы использовать синтаксис записей с именованными полями, чтобы автоматически получать функцию, извлекающую список из типа