52700.fb2
ные. Главное в этой аналогии это то, что мы ничего не меняем, а лишь перекладываем содержимое из одной
структуры в другую.
В Haskell это можно описать так:
onlyOne :: [a] -> Maybe a
onlyOne []
= Nothing
onlyOne (a:as)
= Just a
В этой функции мы перекладываем элементы из списка [a] в частично определённое значение Maybe.
Тоже самое происходит и в функции concat:
230 | Глава 15: Теория категорий
concat :: [[a]] -> [a]
Элементы перекладываются из списка списков в один список. В теории категорий этот процесс называ-
ется естественным преобразованием. Структуры определяются функторами. Поэтому в определении будет
участвовать два функтора. В функции onlyOne это были функторы [] и Maybe. При перекладывании элемен-
тов мы можем просто выбросить все элементы:
burnThemALl :: [a] -> ()
burnThemAll = const ()
Можно сказать, что единичный тип также определяет функтор. Это константный функтор, он переводит
любой тип в единственное значение (), а функцию в id:
data Empty a = Empty
instance Functor Empty where
fmap = const id
Тогда тип функции burnThemAll будет параметризован и слева и справа от стрелки:
burnThemAll :: [a] -> Empty a
burnThemAll = const Empty
Пусть даны две категории A и B и два функтора F, G : A → B. Преобразованием (transformation) в B из
F в G называют семейство стрелок ε:
εA : F A →B GA
для любого A из A
Рассмотрим преобразование onlyOne :: [a] -> Maybe a. Категории A и B в данном случае совпадают~–
это категория Hask. Функтор F – это список, а функтор G это Maybe. Преобразование onlyOne для каждого
объекта a из Hask определяет стрелку
onlyOne :: [a] -> Maybe a
Так мы получаем семейство стрелок, параметризованное объектом из Hask:
onlyOne :: [Int] -> Maybe Int
onlyOne :: [Char] -> Maybe Char
onlyOne :: [Int -> Int] -> Maybe (Int -> Int)
...
...
Теперь давайте определим, что значит перекладывать из одной структуры в другую, не меняя содержа-
ния. Представим, что функтор – это контейнер. Мы можем менять его содержание с помощью метода fmap.
Например мы можем прибавить единицу ко всем элементам списка xs с помощью выражения fmap (+1) xs.
Точно так же мы можем прибавить единицу к частично определённому значению. С точки зрения теории ка-
тегорий суть понятия “останется неизменным при перекладывании” заключается в том, что если мы возьмём
любую функцию к примеру прибавление единицы, то нам неважно когда её применять до функции onlyOne
или после. И в том и в другом случае мы получим одинаковый ответ. Давайте убедимся в этом:
onlyOne $ fmap (+1) [1,2,3,4,5]
=>