Punto de vista, es Un poco extraño, generalmente hablando, una abstracción que no va a ser tanto más poderoso y más general que el de algunos otros de la abstracción; los dos están en desacuerdo. Tener "más poder", significa saber más acerca de la estructura de lo que usted está trabajando, lo que significa más restricciones. En un extremo, de saber exactamente qué tipo usted está trabajando. Esto es extremadamente potente; se puede aplicar cualquier función válida. Por otro lado, tampoco es general en lo más mínimo: el código escrito con este supuesto sólo se aplica a ese tipo! En el otro extremo, se puede saber nada acerca de su tipo (por ejemplo, tener un tipo de variable a
). Esto es muy general, se aplica a cada tipo, pero también no es poderoso, ya que usted no tiene la información suficiente para hacer nada en absoluto!
Un ejemplo más arraigada en el código real es la diferencia entre Functor
y Applicative
. Aquí, Functor
es más general--estrictamente más tipos de Functor
s de Applicative
s, ya que cada Applicative
es también una Functor
pero no viceversa. Sin embargo, desde Applicative
lleva más de la estructura, es estrictamente más potente. Con Functor
, sólo puedes mapa de un solo argumento de las funciones de su tipo; con Applicative
, puede asignar funciones de cualquier número de argumentos. De nuevo: uno es más general, el otro más potente.
Así que es? Las flechas que se encuentran más potentes o más general que las mónadas? Esta es una pregunta más difícil de comparar functors, aplicativo functors y mónadas porque flechas son muy diferentes a las de la bestia. Incluso tienen un tipo diferente: las mónadas et al tener un tipo * -> *
donde las flechas tienen tipo * -> * -> *
. Felizmente, resulta que podemos identificar flechas con aplicativo functors/mónadas, por lo que podemos responder a esta pregunta de manera significativa: las flechas son más generales que las mónadas y, en consecuencia, menos potente. Dado cualquier mónada, podemos construir una flecha fuera de él, pero no podemos construir una monada para cada flecha.
La idea básica es la siguiente:
instance Monad m => Category (a -> m b) where
id = return
(f . g) x = g x >>= f
instance Monad m => Arrow (a -> m b) where
arr f = return . f
first f (x, y) = f x >>= \ x' -> return (x', y)
Sin embargo, ya que tienen una flecha instancia para a -> b
, tenemos que rodear a -> m b
a una newtype
en el código real. Este newtype
se llama Klesli
(debido a Klesli categorías).
Sin embargo, no podemos ir a otro lado-no existe la construcción de obtener un Monad
de cualquier Arrow
. Esto sucede porque un Arrow
cálculo no puede cambiar su estructura basada en los valores que fluye a través de él, mientras que las mónadas puede. La única forma de evitar esto es para añadir potencia a la flecha de su abstracción con más primitiva de la función; esto es exactamente lo ArrowApply
.
El >>>
operador de flechas es una generalización de .
para las funciones, y por lo tanto tiene las mismas restricciones generales. >>=
, por otro lado, es más como una generalización de la función de la aplicación. Nota los tipos: para >>>
, ambos lados están flechas; >>=
, el primer argumento es un valor (m a
) y la segunda de una función. Por otra parte, el resultado de >>>
es otra flecha donde el resultado de >>=
es un valor. Desde flechas sólo tiene >>>
pero hay noción equivalente a >>=
, que no se puede "aplicar" a los argumentos en general, que sólo se puede construir flecha tuberías. El real aplicar/ejecutar la función tendría que ser específico para cualquier flecha. Las mónadas, por otro lado, se definen en términos de >>=
, y así con una cierta noción de la aplicación por defecto.
ArrowApply
sólo se extiende flechas app
, que es una noción general de la aplicación. Imaginemos la función normal de la aplicación:
apply :: (b -> c) -> b -> c
apply f x = f x
podemos uncurry esto para obtener:
apply :: ((b -> c), b) -> c
El camino de las flechas de generalizar las funciones es, básicamente, mediante la sustitución de ->
con una variable (a
). Vamos a hacer esto para apply
mediante la sustitución de los dos accesos de la ->
con un infijo a
:
apply :: (b `a` c, b) `a` c
Todavía podemos ver la misma estructura que la primera versión de apply
, sólo uncurried y con `a`
en lugar de ->
. Ahora si que se acaba de deshacerse de las comillas simples inclinadas y hacer a
prefijo, se obtiene la firma de app
:
app :: a (a b c, b) c
Así vemos cómo ArrowApply
sólo añade una cierta noción de la aplicación de las flechas. Este es un prallel a >>=
, que es un concepto de aplicación de las mónadas (o, en particular, las funciones de la forma a -> m b
). Esto es suficiente estructura adicional para construir una monada de una flecha, por lo ArrowApply
es isomorfo a Monad
.
¿Por qué queremos utilizar estas? Honestamente, no creo que lo haría. Las flechas son bastante sobrevalorado, por lo que se adhieren a las mónadas y aplicativo functors.