Можем ли мы решить это уравнение для X?
Аппликация - это монада, что X является comonad
Можем ли мы решить это уравнение для X?
Аппликация - это монада, что X является comonad
Подумав немного, я думаю, что это на самом деле задний вопрос. Можно подумать, что ComonadApply
для Comonad
то же, что Applicative
для Monad
, но это не так. Но чтобы увидеть это, давайте использовать иерархию классов типов PureScript:
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Apply f where
apply :: f (a -> b) -> f a -> f b -- (<*>)
class Apply f => Applicative f where
pure :: a -> f a
class Applicative m => Monad m where
bind :: m a -> (a -> m b) -> m b -- (>>=)
-- join :: m (m a) -> m a
-- join = flip bind id
Как видите, ComonadApply
- это просто (Apply w, Comonad w) => w
. Тем не менее, Applicative
способность вводить значения в функтор с pure
является реальной разницей.
Определение Comonad
как категориального дуала состоит из return
двойного extract
и двойного extend
bind
(или альтернативного определения через duplicate
качестве двойного join
):
class Functor w => Comonad w where
extract :: w a -> a
extend :: (w a -> b) -> w a -> w b
-- extend f = fmap f . duplicate k
-- duplicate :: w a -> w (w a)
-- duplicate = extend id
Итак, если мы посмотрим на шаг от Applicative
к Monad
, логическим шагом между ними будет класс типов с pure
двойственным типом:
class Apply w => Extract w where
extract :: w a -> a
class Extract w => Comonad w where
extend :: (w a -> b) -> w a -> w b
Обратите внимание, что мы не можем определить extract
в терминах extend
или duplicate
, а также мы не можем определить pure
/return
в терминах bind
или join
, поэтому это выглядит как "логический" шаг. apply
здесь в основном не имеет значения; это может быть определено для Extract
или Monad
, пока их законы держатся:
applyC f = fmap $ extract f -- Comonad variant; needs only Extract actually (*)
applyM f = bind f . flip fmap -- Monad variant; we need join or bind
Таким образом, Extract
(получение значений) для Comonad
является Comonad
что Applicative
(получение значений) для Monad
. Apply
это более или менее счастливый случай на своем пути. Было бы интересно, есть ли в Hask типы, которые имеют Extract
, но не Comonad
(или Extend
но не Comonad
, см. Ниже), но я думаю, что они довольно редки.
Обратите внимание, что Extract
не существует - пока. Но ни один не сделал Applicative
в отчете за 2010 год. Кроме того, любой тип, который одновременно является экземпляром Extract
и Applicative
является одновременно Monad
и Comonad
, поскольку вы можете определить bind
и extend
в терминах extract
и pure
:
bindC :: Extract w => w a -> (a -> w b) -> w b
bindC k f = f $ extract k
extendM :: Applicative w => (w a -> b) -> w a -> w b
extendM f k = pure $ f k
* Возможность определить apply
в терминах extract
является признаком того, что class Extend w => Comonad w
может быть более выполнимым, но можно было бы разбить Monad
на class (Applicative f, Bind f) => Monad f
и, следовательно, Comonad
в (Extend w, Extract w) => Comonad w
, чтобы он более-менее раскалывал волосы.
Мне кажется, что класс Apply
вообще не должен быть частью картины.
Например, определение apply
в ответе @Zeta выглядит не очень корректно. В частности, он всегда отбрасывает контекст первого аргумента и использует только контекст второго аргумента.
Интуитивно кажется, что comonad - это "разделение" контекста, а не объединение, и поэтому "совместное применение" должно быть одинаковым.
На этот вопрос, кажется, есть лучшие ответы: существует ли понятие комападативных функторов, сидящих между комонадами и функторами? ,