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)