Я пришел к этому посту, чтобы лучше понять вывод печально известной цитаты из « Теории категорий Мак Лэйна для рабочего математика» .
При описании того, что является чем-то, часто одинаково полезно описать, что это не так.
Тот факт, что Mac Lane использует описание для описания монады, можно предположить, что она описывает нечто уникальное для монад. Потерпите меня. Чтобы развить более широкое понимание заявления, я полагаю, что необходимо дать понять, что он не описывает нечто уникальное для монад; утверждение одинаково описывает Аппликатив и Стрелки среди других. По той же причине у нас может быть два моноида на Int (Sum и Product), у нас может быть несколько моноидов на X в категории эндофункторов. Но есть еще больше сходства.
И Monad, и Applicative соответствуют критериям:
В операторе используется «Категория ...» Это определяет область действия оператора. В качестве примера Категория 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 + функтор
:: f a -> f b
(т. е. любой один параметризованный тип к тому же параметризованному типу) ... по-другому,
- моноид в категории эндофунктор
Итак, где же сила этой конструкции? Чтобы оценить всю динамику, мне нужно было увидеть, что типичные рисунки моноида (один объект с чем-то вроде стрелки-идентификатора :: single object -> single object
) не иллюстрируют, что мне разрешено использовать стрелку, параметризованную любым количеством значений моноидов, из объекта одного типа, разрешенного в Monoid. Определение эквивалентности стрелки endo, ~ identity игнорирует значение типа функтора, а также тип и значение самого внутреннего слоя «полезной нагрузки». Таким образом, эквивалентность возвращается 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
который ничего не говорит о полезной нагрузке)
- бесконечный диапазон как типа, так и значений для самого внутреннего слоя
В Haskell важно уточнить применимость этого утверждения. Мощь и универсальность этой конструкции не имеет абсолютно никакого отношения к монаде как таковой . Другими словами, конструкция не полагается на то, что делает монаду уникальной.
При попытке выяснить, следует ли создавать код с общим контекстом для поддержки вычислений, которые зависят друг от друга, по сравнению с вычислениями, которые могут выполняться параллельно, это печально известное утверждение, как бы оно ни описывалось, не является контрастом между выбором Аппликатив, Стрелы и Монады, а скорее это описание того, насколько они одинаковы. Для данного решения утверждение является спорным.
Это часто неправильно понимают. Утверждение далее описывается 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», который мне мог бы указать при навигации по Category, чтобы лучше понять идиомы, используемые в Haskell. Ему удается захватить всю мощь мощных вычислительных возможностей, которые чудесно доступны в Haskell.
Тем не менее, есть ирония в том, что я впервые неправильно понял применимость заявления за пределами монады, и то, что я надеюсь передать здесь. Все, что он описывает, оказывается похожим между Applicative и Monads (и Arrows среди других). Чего не говорится, так это небольшого, но полезного различия между ними.
- E