Грубо говоря, Haskell объединяет свою теорию категорий только в одну категорию, чьи объекты являются типами Haskell и чьи стрелки являются функциями между этими типами.Это определенно не язык общего назначения для моделирования теории категорий.
(математический) функтор - это операция, превращающая вещи в одной категории в вещи в другой, возможно, совершенно другой категории.Тогда endofunctor - это функтор, который имеет одинаковые исходные и целевые категории.В Haskell функтор - это операция, превращающая вещи в категории типов Haskell в другие вещи, в том числе и в категорию типов Haskell, поэтому он всегда является эндофунктором.
[Если вы следуете математической литературе,технически операция '(a-> b) -> (ma -> mb)' - это просто часть стрелки эндофунктора m, а 'm' - это часть объекта ]
Когда Хаскелеры говорят о работе «в монаде», они действительно имеют в виду работу в категории монады Клейсли.Поначалу категория монады Клейсли - это совершенно сбивающий с толку зверь, и обычно для ее объяснения требуются как минимум два цвета чернил, поэтому сделайте следующую попытку, чтобы узнать, что это такое, и посмотрите некоторые ссылки (к сожалению, википедия здесь бесполезна длявсе, кроме прямых определений).
Предположим, у вас есть монада 'm' в категории C типов Haskell.Его категория Клейсли Kl (m) имеет те же объекты, что и C, а именно типы Хаскеля, но стрелка a ~ (f) ~> b в Kl (m) является стрелкой a - (f) -> mb в C. (IЯ использовал волнистую линию в моей стрелке Клейсли, чтобы различить их).Повторим еще раз: объекты и стрелки Kl (C) также являются объектами и стрелками C, но стрелки указывают на другие объекты в Kl (C), чем в C. Если это не кажется вам странным, прочитайте его еще раз.осторожно!
Конкретно рассмотрим монаду Может быть.Его категория Клейсли - это просто набор типов Хаскеля, а стрелки a ~ (f) ~> b являются функциями a - (f) -> Maybe b.Или рассмотрим монаду (State s), у которой стрелки a ~ (f) ~> b являются функциями a - (f) -> (State sb) == a - (f) -> (s -> (s, b)),В любом случае, вы всегда пишете волнистую стрелку как сокращение для того, чтобы что-то сделать с типом кодомена ваших функций.
[Обратите внимание, что State не является монадой, потому что тип State - * -> * -> *, поэтому вам нужно указать один из параметров типа, чтобы превратить его в математическую монаду.]
Пока все хорошо, надеюсь, но предположим, что вы хотите составить стрелки a ~ (f) ~> b и b ~ (g) ~> c.Это действительно функции Хаскелла a - (f) -> mb и b - (g) -> mc, которые вы не можете составить, потому что типы не совпадают.Математическое решение состоит в том, чтобы использовать естественное преобразование «умножение» u: mm-> m монады следующим образом: a ~ (f) ~> b ~ (g) ~> c == a - (f) -> mb -(mg) -> mmc - (u_c) -> mc, чтобы получить стрелку a-> mc, которая является стрелкой Клейсли a ~ (f; g) ~> c, как требуется.
Возможно, конкретный пример помогаетВот.В монаде Maybe вы не можете составлять функции f: a -> Maybe b и g: b -> Maybe c напрямую, но подняв g до
Maybe_g :: Maybe b -> Maybe (Maybe c)
Maybe_g Nothing = Nothing
Maybe_g (Just a) = Just (g a)
и используя «очевидный»
u :: Maybe (Maybe c) -> Maybe c
u Nothing = Nothing
u (Just Nothing) = Nothing
u (Just (Just c)) = Just c
Вы можете сформировать композицию u . Maybe_g . f
, которая является функцией a -> Может быть, c, которую вы хотели.
В монаде (State s) она похожа, но более сложна: учитывая две монадические функции a~ (f) ~> b и b ~ (g) ~> c, которые на самом деле являются a - (f) -> (s -> (s, b)) и b - (g) -> (s -> (s, в)) под капотом вы составляете их, поднимая g в
State_s_g :: (s->(s,b)) -> (s->(s,(s->(s,c))))
State_s_g p s1 = let (s2, b) = p s1 in (s2, g b)
, затем применяете естественное преобразование «умножение» u, которое равно
u :: (s->(s,(s->(s,c)))) -> (s->(s,c))
u p1 s1 = let (s2, p2) = p1 s1 in p2 s2
, что) включает конечное состояние f
в начальное состояние g
.
В Haskell это оказывается немного неестественным способом работы, так что вместо этого есть функция (>>=)
, которая в основном делает то же самое, что и вы, но таким образом, чтобы ее было проще реализовать и использовать. Это важно: (>>=)
- это не естественная трансформация 'u'.Вы можете определить каждый в терминах другого, поэтому они эквивалентны, но это не одно и то же.Версия 'u' на Haskell написана join
.
. В этом определении категорий Клейсли отсутствует еще одна вещь - это тождество каждого объекта: ~ (1_a) ~> a, которое на самом деле является - (n_a) -> ma, где n - естественное преобразование «единицы».Это написано return
на Хаскеле, и, кажется, не вызывает такой путаницы.
Я изучил теорию категорий, прежде чем пришел в Хаскелл, и у меня тоже возникли трудности с несоответствием между тем, что математики называютмонада и как они выглядят в Хаскеле.С другого направления не легче!