haskell functional-programming bind monads category-theory

haskell - ¿El operador monad bind(>>=) está más cerca de la composición de la función(encadenamiento) o la aplicación de la función?



functional-programming monads (2)

Claramente, >>= no es una forma de representar la composición de funciones . La composición de funciones se realiza simplemente con . . Sin embargo, tampoco creo que ninguno de los artículos que haya leído signifique esto.

Lo que querían decir era "actualizar" la composición de funciones para trabajar directamente con "funciones monádicas", es decir, funciones de la forma a -> mb . El término técnico para tales funciones es flechas de Kleisli , y de hecho se pueden componer con <=< o >=> . (Alternativamente, puede usar la instancia de Category , luego también puede componerlas con . O >>> .)

Sin embargo, hablar de flechas / categorías tiende a ser confuso, especialmente para los principiantes, al igual que las definiciones de funciones ordinarias sin puntos a menudo son confusas. Afortunadamente, Haskell nos permite expresar funciones también en un estilo más familiar que se centra en los resultados de las funciones, más bien en las funciones mismas como morfismos abstractos . Se hace con abstracción lambda: en lugar de

q = h . g . f

puedes escribir

q = (/x -> (/y -> (/z -> h z) (g y)) (f x))

... por supuesto, el estilo preferido sería (¡esto es solo azúcar sintáctico para la abstracción lambda!)

q x = let y = f x z = g y in h z

Observe cómo, en la expresión lambda, básicamente la composición fue reemplazada por la aplicación:

q = /x -> (/y -> (/z -> h z) $ g y) $ f x

Adaptado a las flechas de Kleisli, esto significa en lugar de

q = h <=< g <=< f

usted escribe

q = /x -> (/y -> (/z -> h z) =<< g y) =<< f x

que de nuevo se ve mucho mejor con operadores invertidos o azúcar sintáctico:

q x = do y <- f x z <- g y h z

Entonces, de hecho, =<< es a <=< como $ es a . . La razón por la que todavía tiene sentido llamarlo operador de composición es que, además de "aplicar a los valores", el operador >>= también hace el bit no trivial sobre la composición de la flecha de Kleisli, que función composición no necesita: unir las capas monádicas .

La razón por la que esto funciona es que Hask es una categoría cerrada cartesiana , en particular una categoría bien puntiaguda . En dicha categoría, las flechas pueden, en términos generales, definirse mediante la recopilación de todos sus resultados cuando se aplican a valores de argumentos simples.

@adamse comenta que let no es realmente azúcar sintáctica para la abstracción lambda. Esto es particularmente relevante en el caso de definiciones recursivas, que no puedes escribir directamente con una lambda. Pero en casos simples como este, let que se comporte como el azúcar sintáctico para lambdas, al igual do notación es azúcar sintáctico para lambdas y >>= . (Por cierto, hay una extensión que permite la recursión incluso en notación do ... evita la restricción lambda mediante el uso de combinadores de punto fijo).

En muchos artículos he leído que mónada >>= operador es una forma de representar la composición de funciones. Pero para mí está más cerca de algún tipo de aplicación de funciones avanzadas.

($) :: (a -> b) -> a -> b (>>=) :: Monad m => m a -> (a -> m b) -> m b

Para la composición tenemos

(.) :: (b -> c) -> (a -> b) -> a -> c (>=>) :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c

Por favor aclarar


Solo como una ilustración, considere esto:

($) :: (a -> b) -> a -> b let g=g in (g $) :: a -> b g :: (a -> b) _____ Functor f => / / (<$>) :: (a -> b) -> f a -> f b let g=g in (g <$>) :: f a -> f b g :: (a -> b) ___________________ Applicative f => / / / (<*>) :: f (a -> b) -> f a -> f b let h=h in (h <*>) :: f a -> f b h :: f (a -> b) _____________ Monad m => /.------. / (=<<) :: (a -> m b) -> m a -> m b let k=k in (k =<<) :: m a -> m b k :: (a -> m b)

Entonces, sí, cada uno de ellos, (g <$>) , (h <*>) o (k =<<) , es algún tipo de aplicación de función, promovida a contexto de Functor, Aplicativo o Monad " ". Y (g $) es solo un tipo regular de aplicación de un tipo regular de función.

Con Functors, las funciones no tienen influencia en el componente f de la cosa general. Trabajan estrictamente en el interior y no pueden influir en la "envoltura" .

Con los aplicantes, las funciones vienen envueltas en una f , cuyo ajuste se combina con el de un argumento (como parte de la aplicación) para producir el ajuste del resultado.

Con Monads, las funciones mismas ahora producen los resultados ajustados, sacando sus argumentos de alguna manera del argumento ajustado (como parte de la aplicación).

Podemos ver a los tres operadores como una especie de marca en una función, como a los matemáticos les gusta escribir digamos f'' o f^ o f* (y en el trabajo original de Eugenio Moggi (1) f* es exactamente lo que se usó, denotando la función promovida (f =<<) ).

Y, por supuesto, con las funciones promocionadas :: fa -> fb , podemos encadenarlas, porque ahora los tipos se alinean. La promoción es lo que permite la composición.

(1) "Nociones de computación y mónadas", Eugenio Moggi, julio de 1991.

Entonces el functor está "trabajando mágicamente dentro" de "las tuberías"; aplicativo es "tuberías prefabricadas construidas a partir de componentes de antemano"; y las mónadas están "construyendo redes de tuberías a medida que avanzamos". Una ilustración: