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

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

На деле вы можете воспринимать декларации >newtype как декларации >data, только с одним конструктором данных и одним полем. Если вы поймаете себя на написании такого объявления, рассмотрите использование >newtype.

Ключевое слово >data предназначено для создания ваших собственных типов данных. Ими вы можете увлечься не на шутку. Они могут иметь столько конструкторов и полей, сколько вы пожелаете, и использоваться для реализации любого алгебраического типа данных – всего, начиная со списков и >Maybe-подобных типов и заканчивая деревьями.

Подведём итог вышесказанному. Используйте ключевые слова следующим образом:

• если вы просто хотите, чтобы ваши сигнатуры типов выглядели понятнее и были более наглядными, вам, вероятно, нужны синонимы типов;

• если вы хотите взять существующий тип и обернуть его в новый, чтобы определить для него экземпляр класса типов, скорее всего, вам пригодится >newtype;

• если вы хотите создать что-то совершенно новое, есть шанс, что вам поможет ключевое слово >data.

В общих чертах о моноидах

Классы типов в языке Haskell используются для представления интерфейса к типам, которые обладают неким схожим поведением. Мы начали с простых классов типов вроде класса >Eq, предназначенного для типов, значения которых можно сравнить, и класса >Ord – для сущностей, которые можно упорядочить. Затем перешли к более интересным классам типов, таким как классы >Functor и >Applicative.



Создавая тип, мы думаем о том, какие поведения он поддерживает (как он может действовать), а затем решаем, экземпляры каких классов типов для него определить, основываясь на необходимом нам поведении. Если разумно, чтобы значения нашего типа были сравниваемыми, мы определяем для нашего типа экземпляр класса >Eq. Если мы видим, что наш тип является чем-то вроде функтора – определяем для него экземпляр класса >Functor, и т. д.

Теперь рассмотрим следующее: оператор >* – это функция, которая принимает два числа и перемножает их. Если мы умножим какое-нибудь число на >1, результат всегда равен этому числу. Неважно, выполним ли мы >1 * x или >x * 1 – результат всегда равен