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

. Если мы посмотрим на определение класса >Functor ещё раз:

>class Functor f where

>   fmap :: (a –> b) –> f a –> f b

то увидим, что переменная типа >f используется как тип, принимающий один конкретный тип для того, чтобы создать другой. Мы знаем, что возвращается конкретный тип, поскольку он используется как тип значения в функции. Из этого можно заключить, что типы, которые могут «подружиться» с классом >Functor, должны иметь сорт >*>–>>*.

Ну а теперь займёмся тип-фу. Посмотрим на определение такого класса типов:

>class Tofu t where

>   tofu :: j a –> t a j

Объявление выглядит странно. Как мы могли бы создать тип, который будет иметь экземпляр такого класса? Посмотрим, каким должен быть сорт типа. Так как тип >j a используется как тип значения, который функция >tofu принимает как параметр, у типа >j a должен быть сорт *. Мы предполагаем сорт >* для типа >a и, таким образом, можем вывести, что тип >j должен быть сорта >* –> *. Мы видим, что тип >t также должен производить конкретный тип, и что он принимает два типа. Принимая во внимание, что у типа >a сорт >* и у типа >j сорт >* –> *, мы выводим, что тип >t должен быть сорта >* –> (* –> *) –> *. Итак, он принимает конкретный тип >(a) и конструктор типа, который принимает один конкретный тип >(j), и производит конкретный тип. Вау!

Хорошо, давайте создадим тип такого сорта: >* –> (* –> *) –> *. Вот один из вариантов:

>data Frank a b = Frank {frankField :: b a} deriving (Show)

Откуда мы знаем, что этот тип имеет сорт >* –> (* –> *) – > *? Именованные поля в алгебраических типах данных сделаны для того, чтобы хранить значения, так что они по определению должны иметь сорт >*. Мы предполагаем сорт >* для типа >a; это означает, что тип >b принимает один тип как параметр. Таким образом, его сорт – >* –>>*. Теперь мы знаем сорта типов >a и >b; так как они являются параметрами для типа >Frank, можно показать, что тип >Frank имеет сорт >* –> (* –> *) – > *. Первая >* обозначает сорт типа >a; >(*>–> *) обозначает сорт типа >b. Давайте создадим несколько значений типа >Frank и проверим их типы.

>ghci> :t Frank {frankField = Just "ХА-ХА"}

>Frank {frankField = Just "ХА-ХА"} :: Frank [Char] Maybe

>ghci> :t Frank {frankField = Node 'a' EmptyTree EmptyTree}

>Frank {frankField = Node 'a' EmptyTree EmptyTree} :: Frank Char Tree

>ghci> :t Frank {frankField = "ДА"}

>Frank {frankField = "ДА"} :: Frank Char []

Гм-м-м… Так как поле >frankField имеет тип вида >a b, его значения должны иметь типы похожего вида. Например, это может быть >Just "ХА-ХА", тип в этом примере – >Maybe [Char], или >['Д','А'] (тип