Я пришел к этому посту, чтобы лучше понять вывод печально известной цитаты из теории категорий Мак Лейна для рабочего математика .
При описании того, что есть, часто одинаково полезно описывать, что это не так.
Тот факт, что Mac Lane использует описание для описания монады, можно предположить, что она описывает нечто уникальное для монад. Потерпите меня. Чтобы развить более широкое понимание этого утверждения, я полагаю, что необходимо дать понять, что он не описывает что-то уникальное для монад; утверждение одинаково описывает Аппликатив и Стрелки среди других. По той же причине у нас может быть два моноида на Int (Sum и Product), у нас может быть несколько моноидов на X в категории эндофункторов. Но есть еще больше общих черт.
И Монада, и Аппликатив соответствуют критериям:
В операторе используется «Категория ...» Это определяет область действия оператора. В качестве примера Категория Functor описывает область действия f * -> g *
, то есть Any functor -> Any functor
, например, Tree * -> List *
или Tree * -> Tree *
.
То, что не указано в категориальном утверждении, описывает, где что-либо и все разрешено .
В этом случае внутри функторов не указывается * -> *
aka a -> b
, что означает Anything -> Anything including Anything else
. Поскольку мое воображение переходит к Int -> String, оно также включает Integer -> Maybe Int
или даже Maybe Double -> Either String Int
, где a :: Maybe Double; b :: Either String Int
.
Итак, утверждение сводится к следующему:
- область действия функтора
:: f a -> g b
(т. Е. Любой параметризованный тип для любого параметризованного типа)
- endo + functor
:: f a -> f b
(т. Е. Любой один параметризованный тип к одному и тому же параметризованному типу) ... иначе говоря,
- моноид в категории эндофунктор
Так, где сила этой конструкции? Чтобы оценить всю динамику, мне нужно было увидеть, что типичные рисунки моноида (одиночный объект с чем-то вроде стрелки идентичности, :: single object -> single object
) не иллюстрируют, что мне разрешено использовать стрелку, параметризованную с помощью любое число моноидных значений из объекта типа one , разрешенного в Monoid. Эндо, ~ определение стрелки идентичности игнорирует значение типа функтора , а также тип и значение самого внутреннего слоя "полезной нагрузки". Таким образом, эквивалентность возвращает true
в любой ситуации, когда совпадают функторные типы (например, Nothing -> Just * -> Nothing
эквивалентно Just * -> Just * -> Just *
, поскольку они оба Maybe -> Maybe -> Maybe
).
Боковая панель: ~ снаружи является концептуальным, но является самым левым символом в f a
. Он также описывает, что «Хаскелл» читает первым (большая картинка); так что тип "снаружи" по отношению к значению типа. Взаимосвязь между слоями (цепочкой ссылок) в программировании нелегко установить в категории. Категория набора используется для описания типов (Int, Strings, Maybe Int и т. Д.), Которые включают в себя категорию функторов (параметризованные типы). Цепочка ссылок: тип функтора, значения функтора (элементы набора этого функтора, например, Nothing, Just) и, в свою очередь, все остальное, на которое указывает значение каждого функтора. В категории отношения описываются по-разному, например, return :: a -> m a
считается естественным преобразованием из одного функтора в другой, в отличие от всего, что упоминалось до сих пор.
Возвращаясь к основному потоку, в общем, для любого определенного тензорного произведения и нейтрального значения, в итоге утверждение описывает удивительно мощную вычислительную конструкцию, порожденную ее парадоксальной структурой:
- снаружи он выглядит как отдельный объект (например,
:: List
); Статическая
- но внутри, допускает большую динамику
- любое количество значений того же типа (например, Empty | ~ NonEmpty), что и fodder для функций любой арности. Тензорное произведение уменьшит любое количество входов до единого значения ... для внешнего слоя (~
fold
, который ничего не говорит о полезной нагрузке)
- бесконечный диапазон обоих типа и значений для самого внутреннего слоя
В Хаскеле важно уточнить применимость этого утверждения. Мощь и универсальность этой конструкции не имеет абсолютно никакого отношения к монаде как таковой . Другими словами, конструкция не полагается на то, что делает монаду уникальной.
При попытке выяснить, следует ли создавать код с общим контекстом для поддержки вычислений, которые зависят друг от друга, по сравнению с вычислениями, которые могут выполняться параллельно, это позорное утверждение, как бы оно ни описывалось, не является контрастом между выбор Applicative, Arrows и Monads, а точнее это описание того, насколько они одинаковы. Для данного решения утверждение является спорным.
Это часто неправильно понимают. Утверждение продолжает описывать join :: m (m a) -> m a
как тензорное произведение для моноидального эндофунктора. Тем не менее, в нем не сформулировано, как в контексте этого утверждения также можно было бы выбрать (<*>)
. Это действительно пример шести / полдюжины. Логика объединения значений абсолютно одинакова; один и тот же вход генерирует одинаковый выход из каждого (в отличие от моноидов Sum и Product для Int, поскольку они генерируют разные результаты при объединении Ints).
Итак, резюмируем: моноид в категории эндофункторов описывает:
~t :: m * -> m * -> m *
and a neutral value for m *
(<*>)
и (>>=)
оба обеспечивают одновременный доступ к двум m
значениям для вычисления единственного возвращаемого значения. Логика, используемая для вычисления возвращаемого значения, точно такая же. Если бы не различные формы функций, которые они параметризуют (f :: a -> b
против k :: a -> m b
) и положение параметра с одинаковым типом возвращаемого значения вычисления (т. Е. a -> b -> b
против b -> a -> b
для каждого соответственно) Я подозреваю, что мы могли бы параметризировать моноидальную логику, тензорное произведение, для повторного использования в обоих определениях. В качестве упражнения, чтобы понять суть, попробуйте реализовать ~t
, и вы получите (<*>)
и (>>=)
в зависимости от того, как вы решите его определить forall a b
.
Если моя последняя точка концептуально верна как минимум, тогда она объясняет точное и единственное вычислительное различие между Applicative и Monad: функции, которые они параметризуют. Другими словами, разница внешняя в реализации классов этих типов.
В заключение, по моему собственному опыту, печально известная цитата Мак Лэйна предоставила мне замечательный мем "goto", который мне мог бы указать при навигации по категории, чтобы лучше понять идиомы, используемые в Haskell. Ему удается захватить всю мощь мощных вычислительных возможностей, которые чудесно доступны в Haskell.
Однако есть ирония в том, что я впервые неправильно понял применимость утверждения за пределами монады, и то, что, я надеюсь, передается здесь. Все, что он описывает, оказывается тем же, что и между Применимым и Монадой (и Стрелками среди других). Чего не говорится, так это небольшого, но полезного различия между ними.
- E