Arrows
обобщены по категориям и, таким образом, по классу типов Category
.
class Category f where
(.) :: f a b -> f b c -> f a c
id :: f a a
Определение класса типов Arrow
имеет Category
как суперкласс.Категории (в смысле haskell) обобщают функции (вы можете их составлять, но не применять их) и поэтому, безусловно, являются «моделью вычислений».Arrow
предоставляет Category
дополнительную структуру для работы с кортежами.Итак, в то время как Category
отражает что-то о функциональном пространстве Haskell, Arrow
распространяет это на что-то о типах продуктов.
Каждый Monad
порождает нечто, называемое «Kleisli Category», и эта конструкция дает вам экземплярыArrowApply
.Вы можете построить Monad
из любого ArrowApply
так, чтобы полный круг не изменил вашего поведения, поэтому в некотором глубоком смысле Monad
и ArrowApply
- это одно и то же.
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)
instance Monad m => Arrow (Kleisli m) where
arr f = Kleisli (return . f)
first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))
Фактически каждый Arrow
порождает Applicative
(универсальное количественное определение для правильной сортировки) в дополнение к Category
суперклассу, и я считаю, что комбинация подходящего Category
и Applicative
достаточно, чтобы восстановить Arrow
.
Итак, эти структуры глубоко связаны.
Внимание: впереди неуместный комментарий .Одно из главных различий между мышлением Functor
/ Applicative
/ Monad
и мышлением Category
/ Arrow
заключается в том, что хотя Functor
и его аналог являются обобщениями на уровне объекта (типы в Haskell), Category
/ Arrow
- это генерация понятия morphism (функции в Haskell).Я считаю, что мышление на уровне обобщенного морфизма предполагает более высокий уровень абстракции, чем мышление на уровне обобщенного объектов .Иногда это хорошо, а иногда нет.С другой стороны, несмотря на то, что Arrows
имеют категориальную основу, и никто по математике не считает Applicative
интересным, я понимаю, что Applicative
обычно лучше понимают, чем Arrow
.
В основном вы можете думать о «Category
Более конкретно ниже: Что касается других структур для моделирования вычислений: часто можно поменять направление «стрелок» (просто обозначающих здесь морфизмы) в категориальных конструкциях, чтобы получить «двойное» или «совместное»строительство".Итак, если монада определена как
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
(хорошо, я знаю, что Хаскелл определяет вещи не так, но ma >>= f = join $ fmap f ma
и join x = x >>= id
, так что это вполне может быть), тогда комонадis
class Functor m => Comonad m where
extract :: m a -> a -- this is co-return
duplicate :: m a -> m (m a) -- this is co-join
Эта штука также довольно распространена.Оказывается, Comonad
является базовой структурой клеточных автоматов .Для полноты, я должен отметить, что Control.Comonad
Эдварда Кметта помещает duplicate
в класс между функтором и Comonad
для "расширяемых функторов", потому что вы также можете определить
extend :: (m a -> b) -> m a -> m b -- Looks familiar? this is just the dual of >>=
extend f = fmap f . duplicate
--this is enough
duplicate = extend id
Оказывается, что всеMonad
s также являются "расширяемыми"
monadDuplicate :: Monad m => m a -> m (m a)
monadDuplicate = return
, в то время как все Comonads
являются "присоединяемыми"
comonadJoin :: Comonad m => m (m a) -> m a
comonadJoin = extract
, поэтому эти структуры очень близки друг к другу.