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

может использоваться для создания ваших новых типов с нуля, ключевое слово >newtype предназначено для создания совершенно нового типа из существующего. Сравнение значений деклараций >newtype с образцом не похоже на вынимание содержимого коробки (что характерно для деклараций >data); это скорее представляет собой прямое преобразование из одного типа в другой.

Ключевое слово type против newtype и data

К этому моменту, возможно, вы с трудом улавливаете различия между ключевыми словами >type, >data и >newtype. Поэтому давайте немного повторим пройденное.

Ключевое слово >type предназначено для создания синонимов типов. Мы просто даём другое имя уже существующему типу, чтобы на этот тип было проще сослаться. Скажем, мы написали следующее:

>type IntList = [Int]

Всё, что это нам даёт, – возможность сослаться на тип >[Int] как >IntList. Их можно использовать взаимозаменяемо. Мы не получаем конструктор данных >IntList или что-либо в этом роде. Поскольку идентификаторы >[Int] и >IntList являются лишь двумя способами сослаться на один и тот же тип, неважно, какое имя мы используем в наших аннотациях типов:

>ghci> ([1,2,3] :: IntList) ++ ([1,2,3] :: [Int])

>[1,2,3,1,2,3]

Мы используем синонимы типов, когда хотим сделать наши сигнатуры типов более наглядными. Мы даём типам имена, которые говорят нам что-либо об их предназначении в контексте функций, где они используются. Например, когда мы использовали ассоциативный список типа >[(String,String)] для представления телефонной книги в главе 7, то дали ему синоним типа >PhoneBook, чтобы сигнатуры типов наших функций легко читались.

Ключевое слово >newtype предназначено для оборачивания существующих типов в новые типы – в основном чтобы для них можно было проще определить экземпляры некоторых классов типов. Когда мы используем ключевое слово >newtype для оборачивания существующего типа, получаемый нами тип отделён от исходного. Предположим, мы определяем следующий тип при помощи декларации >newtype:

>newtype CharList = CharList { getCharList :: [Char] }

Нельзя использовать оператор >++, чтобы соединить значение типа >CharList и список типа >[Char]. Нельзя даже использовать оператор >++, чтобы соединить два значения типа >CharList, потому что оператор >++ работает только со списками, а тип >CharList не является списком, хотя можно сказать, что >CharList содержит список. Мы можем, однако, преобразовать два значения типа >CharList в списки, соединить их с помощью оператора >++, а затем преобразовать получившееся обратно в >CharList.

Когда в наших объявлениях типа >newtype