Ante todo:
Cualquier mónada también es un funtor aplicativo y cualquier funtor aplicativo es un ficticio.
Esto es cierto en el contexto de Haskell, pero (que se lee Applicative
como "functor monoidal fuerte y laxo") no en general, por la razón bastante trivial de que puede tener functores "aplicativos" entre diferentes categorías monoidales, mientras que las mónadas (y comonads) son endofunctores .
Además, la identificación Applicative
con functores monoidales laxos y fuertes es un poco engañoso, porque para justificar el nombre (y la firma de tipo de (<*>)
) se requiere un functor entre las categorías monoidales cerradas que conserva la estructura monoidal y el hom interno . Esto podría llamarse un "functor monoidal cerrado laxo", excepto que un functor entre categorías cerradas monoidales que conserva cualquiera de las propiedades conserva la otra de la manera obvia . Debido a que Applicative
solo describe los endofunctores en Hask preservando la estructura monoidal (,)
, sus instancias obtienen muchas propiedades automáticamente, incluida su resistencia , que por lo tanto se puede eludir.
La conexión aparente con Monad
es posiblemente un artefacto de las limitaciones implícitas en Applicative
hacer coincidir aspectos de sus respectivas estructuras monoides, una feliz coincidencia que desafortunadamente no sobrevive a la dualización.
Así como una comonad en una categoría es una mónada en C o p , un functor monoidal oplax C → D es un functor monoidal laxo C o p → D o p . Pero H a s k o p no está cerrado monoidal , y un co- que no incluye la aplicación de función apenas merece el nombre. De todos modos, el resultado no sería terriblemente interesante:CCop C→DCo p→ Do pHa s ko pApplicative
class (Functor f) => CoMonoidal f where
counit :: f () -> ()
cozip :: f (a, b) -> (f a, f b)
Applicative
Ha s ko pnewtype Op b a = Op (a -> b)
Ha s kb → aHa s ko pOp b a
Ha s k
Ha s kApplicative
class (Functor f) => CoApplicative f where
copure :: f a -> a
coap :: (f a -> f b) -> f (a -> b)
Agregar duplicate :: f a -> f (f a)
a copure
produciría una comonad (suponiendo que se cumplan las leyes), por supuesto. Pero no hay una relación obvia entre, coap
sea lo que sea, y extend :: (f a -> b) -> f a -> f b
. La comparación de los tipos se hace evidente que la dualización está ocurriendo en diferentes formas: las estructuras comonoidal subyacentes duplicate
y cozip
tienen poco que ver entre sí o con coap
(que probablemente no tiene sentido de todos modos), mientras que liftA2 (,)
y (<*>)
son equivalentes y se pueden derivar de join
.
Otra posible forma de dualización Applicative
, que tiene aún menos que ver con comonads, es considerar los functores monoidales contravariantes:
class (Contravariant f) => ContraMonoidal f where
contraunit :: f a
contrazip :: f a -> f b -> f (Either a b)
Ha s ko pb <~ a
contracurry :: (Either c b <~ a) -> (c <~ (b <~ a))
contraapply :: b -> Either a (a <~ b)
Ha s kCoApplicative
Sin embargo, en una categoría cerrada monoidal más hospitalaria para la dualización, es posible que tenga mejor suerte. En particular, creo que ambos Kleisli (Cont r)
y su categoría opuesta son cerrados monoidales, por lo que podría ser un mejor contexto para explorar estas ideas.