what monad haskell functional-programming monads do-notation

what - monad haskell



¿Cuál es el tipo de la variable en do-notation aquí en Haskell? (2)

Los códigos a continuación parecen bastante claros:

do x <- Just 3 y <- Just "!" Just (show x ++ y)

Aquí el tipo de x es Num e y es String . ( <- aquí se usa para sacar valor real de la Mónada)

Sin embargo, este fragmento no parece tan claro para mí:

import Control.Monad.Instances addStuff :: Int -> Int addStuff = do a <- (* 2) b <- (+ 10) return (a + b)

¿Cuál es el tipo de a y tipo de b aquí? Parece que actúan como un Num , pero a <- (* 2) b <- (+ 10) parece críptico aquí ...

¿Alguien tiene ideas sobre esto?


Bueno, te has tropezado con una especie de mónada extraña.

La mónada en cuestión es la Monad ((->) r) . Ahora, ¿qué significa eso? Bueno, es la mónada de funciones de la forma r -> * . Es decir, de funciones que toman el mismo tipo de entrada.

Usted preguntó qué tipo de a y b son en este caso. Bueno, ambos son Num a => a , pero eso realmente no explica mucho.

Intuitivamente, podemos entender la mónada de esta manera: Un valor monádico es una función que toma un valor de tipo r como entrada. Siempre que nos atemos a la mónada, tomamos ese valor y lo pasamos a la función ligada.

Es decir, en nuestro ejemplo addStuff , si llamamos a addStuff 5 , entonces a está obligado a (*2) 5 (que es 10 ), y b está vinculado a (+10) 5 (que es 15 ).

Veamos un ejemplo más simple de esta mónada para tratar de entender cómo funciona exactamente:

mutate = do a <- (*2) return (a + 5)

Si deshacemos esto para un compromiso, obtenemos:

mutate = (*2) >>= (/a -> return (a + 5))

Ahora, esto no ayuda mucho, así que usemos la definición de bind para esta mónada:

mutate = / r -> (/a -> return (a + 5)) ((*2) r) r

Esto se reduce a

mutate = / r -> return ((r*2) + 5) r

Lo cual usando la definición que return es const , se puede reducir a

mutate = / r -> (r*2) + 5

Que es una función, que multiplica un número por 2, y luego agrega 5.

Esa es una mónada extraña.


Dado addStuff

addStuff :: Int -> Int addStuff = do a<-(*2) b<-(+10) return (a+b)

la definición desciende en

addStuff = (* 2) >>= /a -> (+ 10) >>= /b -> return (a + b)

Pasar el cursor sobre el >>= en el editor en línea fpcomplete muestra

:: Monad m => forall a b. (m a ) -> (a -> m b ) -> (m b ) :: (Int -> a ) -> (a -> Int -> b ) -> (Int -> b ) :: (Int -> Int) -> (Int -> Int -> Int) -> (Int -> Int)

Eso nos lleva a creer que usamos una instancia de Monad para funciones. De hecho, si miramos el código fuente , vemos

instance Monad ((->) r) where return = const f >>= k = / r -> k (f r) r

Usando esta información recién obtenida podemos evaluar la función addStuff nosotros mismos.

Dada la expresión inicial

(* 2) >>= ( /a -> (+10) >>= /b -> return (a + b) )

lo sustituimos usando la definición >>= , dándonos (en el siguiente {} , [] , () solo ilustra diferente profundidad de () )

/r1 -> {/a -> (+10) >>= /b -> return (a + b)} {(* 2) r1} r1

simplificar el penúltimo término dentro de la lambda más externa

/r1 -> {/a -> (+10) >>= /b -> return (a + b)} {r1 * 2} r1

aplicar {r1 * 2} a {/a -> ...}

/r1 -> {(+10) >>= /b -> return ((r1 * 2) + b)} r1

sustituir el resto >>= con su definición nuevamente

/r1 -> {/r2 -> [/b -> return (r1 * 2 + b)] [(+10) r2] r2} r1

simplifica el penúltimo término dentro de la lambda interior

/r1 -> {/r2 -> [/b -> return (r1 * 2 + b)] [r2 + 10] r2} r1

aplicar [r2 + 10] a {/b -> ...}

/r1 -> {/r2 -> [return (r1 * 2 + (r2 + 10))] r2} r1

aplicar r1 a {/r2 -> ...}

/r1 -> {return (r1 * 2 + r1 + 10) r1}

return sustitutivo con su definición

/r1 -> {const (r1 * 2 + r1 + 10) r1}

evaluar const x _ = x

/r1 -> {r1 * 2 + r1 + 10}

embellecer

/x -> 3 * x + 10

finalmente obtenemos

addStuff :: Int -> Int addStuff = (+ 10) . (* 3)