haskell - mónada - Cómo extraer valor de la acción monádica
monadico definicion wikipedia (7)
¿Hay una función incorporada con la firma
:: (Monad m) => ma -> a
?
Si Hoogle dice que no hay ... entonces probablemente no exista, asumiendo que su definición de "integrado" está "en las bibliotecas base".
Hoogle dice que no hay tal función. ¿Puedes explicar porque?
¡Eso es fácil, porque Hoogle no encontró ninguna función en las bibliotecas base que coincida con esa firma de tipo!
Más en serio, supongo que estabas pidiendo la explicación monádica. Los problemas son seguridad y significado . (Ver también mis pensamientos previos sobre magicMonadUnwrap :: Monad m => ma -> a
)
Supongamos que le digo que tengo un valor que tiene el tipo [Int]
. Como sabemos que []
es una mónada, esto es similar a decirle que tengo un valor que tiene el tipo Monad m => m Int
. Entonces, supongamos que quieres sacar el Int
de eso [Int]
. Bueno, ¿qué Int
quieres? ¿El primero? ¿El último? ¿Qué pasa si el valor del que te dije es en realidad una lista vacía? En ese caso, ¡ni siquiera hay un Int
para darte! Por lo tanto, para las listas, no es seguro tratar de extraer un único valor de cualquier manera. Incluso cuando es seguro (una lista no vacía), necesita una función específica de la lista (por ejemplo, head
) para aclarar lo que quiere decir deseando f :: [Int] -> Int
. Esperemos que pueda intuir desde aquí que el significado de Monad m => ma -> a
simplemente no está bien definido. Podría tener múltiples significados para la misma mónada, o podría significar absolutamente nada para algunas mónadas, y, a veces, simplemente no es seguro.
¿Hay una función incorporada con la firma :: (Monad m) => ma -> a
?
Hoogle dice que no hay tal función.
¿Puedes explicar porque?
Bueno, técnicamente hay una forma de unsafePerformIO para la mónada IO.
Pero, como el propio nombre lo sugiere, esta función es mala y solo debes usarla si realmente sabes lo que estás haciendo (y si tienes que preguntar si sabes o no, entonces no)
Esto no existe porque Monad
es un patrón para la composición, no un patrón para la descomposición. Siempre puedes juntar más piezas con la interfaz que define. No dice nada acerca de desarmar algo.
Preguntar por qué no se puede sacar algo es como preguntar por qué la interfaz Iterator
de Java no contiene un método para agregar elementos a lo que se está iterando. Simplemente no es para lo que es la interfaz del Iterator
.
Y sus argumentos sobre tipos específicos que tienen un tipo de función extracto siguen de la misma manera. Alguna implementación particular de Iterator
podría tener una función de add
. Pero dado que no es para lo que son los Iterator
, la presencia de ese método en alguna instancia particular es irrelevante.
Y la presencia de fromJust
es tan irrelevante. No es parte del comportamiento que Monad
intenta describir. Otros han dado muchos ejemplos de tipos en los que no hay ningún valor para extract
para trabajar. Pero esos tipos aún son compatibles con la semántica prevista de Monad
. Esto es importante. Significa que Monad
es una interfaz más general de la que le da crédito.
Porque puede no tener sentido (en realidad, no tiene sentido en muchos casos).
Por ejemplo, podría definir una mónada de analizador así:
data Parser a = Parser (String ->[(a, String)])
Ahora no hay absolutamente ninguna forma sensata por defecto para obtener una String
de una Parser String
. En realidad, no hay manera de obtener una Cadena de esto con solo la Mónada.
Probablemente haya una mejor respuesta que esta, pero una forma de ver por qué no puedes tener un tipo (Monad m) => ma -> a
es considerar una mónada nula:
data Null a = Null
instance Monad Null where
return a = Null
ma >>= f = Null
Ahora (Monad m) => ma -> a
significa Null a -> a
, es decir, obtener algo de la nada. No puedes hacer eso.
Supongamos que hay tal función:
extract :: Monad m => m a -> a
Ahora puedes escribir una "función" como esta:
appendLine :: String -> String
appendLine str = str ++ extract getLine
A menos que se garantice que la función de extract
nunca terminará, esto violaría la transparencia referencial, porque el resultado de appendLine "foo"
(a) dependería de algo distinto de "foo"
, (b) evaluaría diferentes valores cuando se evaluara en diferentes contextos.
O en palabras más simples, si hubiera una operación de extract
realmente útil, Haskell no sería puramente funcional.
Una mónada solo proporciona dos funciones:
return :: Monad m => a -> m a
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Ambos devuelven algo de tipo ma
, por lo que no hay forma de combinarlos de ninguna manera para obtener una función de tipo Monad m => ma -> a
. Para hacer eso, necesitarás más que estas dos funciones, por lo que necesitas saber más sobre m
que eso es una mónada.
Por ejemplo, la mónada Identity
tiene runIdentity :: Identity a -> a
, y varias mónadas tienen funciones similares, pero no hay forma de proporcionarlo genéricamente. De hecho, la incapacidad de "escapar" de la mónada es esencial para mónadas como IO
.