Arrows
están generalizados por Categorías, y por lo tanto por la clase de tipo Category
.
class Category f where
(.) :: f a b -> f b c -> f a c
id :: f a a
La definición clase de tipos Arrow
tiene Category
como una superclase. Las categorías (en el sentido haskell) generalizan las funciones (puedes componerlas pero no aplicarlas) y así son definitivamente un "modelo de computación". Arrow
proporciona un Category
con estructura adicional para trabajar con tuplas. Entonces, mientras que Category
refleja algo sobre el espacio de funciones de Haskell, Arrow
se extiende a algo acerca de los tipos de productos.
Cada Monad
da lugar a algo llamado "Categoría Kleisli" y esta construcción le da instancias de ArrowApply
. Puede construir un Monad
de cualquiera de los ArrowApply
de manera que al completar el círculo no cambie su comportamiento, por lo que en un sentido profundo Monad
y son lo mismo.
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))
En realidad todos los Arrow
da lugar a una Applicative
(cuantificada universalmente para obtener el tipo correcto), además de los Category
superclase, y creo que la combinación apropiada de la Category
y Applicative
es suficiente para reconstruir su Arrow
.
Por lo tanto, estas estructuras están profundamente conectadas.
Advertencia: comentario quisquilloso delante. Una diferencia central entre el camino Functor
/Applicative
/Monad
de pensar y la forma Category
/Arrow
de pensar es que mientras Functor
y su clase son generalizaciones a nivel de objeto (tipos en Haskell), Category
/Arrow
son generelazation de la noción de morfismo (funciones en Haskell). Mi creencia es que pensar en el nivel generalizado de morfismo implica un mayor nivel de abstracción que pensar en el nivel de los objetos generalizados. A veces eso es algo bueno, otras veces no lo es. Por otro lado, a pesar del hecho de que Arrows
tiene una base categórica, y nadie en matemáticas piensa que Applicative
es interesante, entiendo que Applicative
se entiende mejor que Applicative
generalmente se entiende mejor que Arrow
.
Básicamente se puede pensar en "Categoría < Flecha < ArrowApply" y "Functor < Aplicativo < mónada" tal que "Categoría Functor ~", "Flecha ~ Aplicativo" y "ArrowApply ~ mónada".
más concreto continuación: En cuanto a otras estructuras para modelar cálculo: a menudo se puede invertir el sentido de las "flechas" (solo significa morfismos aquí) en las construcciones categóricas para obtener el "doble" o "co-construcción ". Por lo tanto, si una mónada se define como
class Functor m => Monad m where
return :: a -> m a
join :: m (m a) -> m a
(bien, sé que no es así como Haskell define cosas, pero ma >>= f = join $ fmap f ma
y join x = x >>= id
por lo que sólo así podía ser) entonces el comonad es
class Functor m => Comonad m where
extract :: m a -> a -- this is co-return
duplicate :: m a -> m (m a) -- this is co-join
Esto también es bastante común. Resulta que Comonad
es la estructura subyacente básica de autómata celular. Por completitud, debo señalar que de Edward Kmett Control.Comonad
pone duplicate
en una clase entre funtor y Comonad
para "extensibles Functors" porque también se pueden definir
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
Resulta que todos Monad
s también son "extensible"
monadDuplicate :: Monad m => m a -> m (m a)
monadDuplicate = return
mientras que todos Comonads
son "acoplable"
comonadJoin :: Comonad m => m (m a) -> m a
comonadJoin = extract
por lo
estas estructuras están muy juntas.
La página Monad vs. Arrows enlaza con un documento que también compara functors aplicativos (también conocidos como modismos). –
Functors aplicativos sin duda * son * buenos en el cómputo composable! De hecho, componen mejor que las mónadas (la composición de dos funtores aplicativos es un funcionador aplicativo, que no se aplica a las mónadas). – ehird