2010-08-01 34 views
23

Mientras mónadas están representados en Haskell usando el enlace y volver funciones, también pueden tener otra representación mediante la función de unir, como discussed here. Sé que el tipo de esta función es M (M (X)) -> M (X), pero ¿qué hace esto realmente?Mónada función unirse

+0

* aplana * an (cómputo efectivo de un (cómputo efectivo)) en un equivalente (cómputo efectivo). Imagine bucles anidados, donde se desenrolla el bucle interno. O como en C, donde la matriz 2D es realmente un vector 1D y un bucle anidado sobre las filas y columnas de la matriz se puede convertir en un bucle simple a lo largo del vector con un esquema de direccionamiento apropiado, excepto que esto funciona incluso para sub-arrays de longitud desigual, y cuando el lazo interno se calcula programáticamente. –

Respuesta

35

En realidad, de alguna manera, join es donde ocurre realmente toda la magia-- (>>=) se usa principalmente para su conveniencia.

Todas las clases de tipo basadas en Functor describen una estructura adicional utilizando algún tipo. Con Functor esta estructura adicional es a menudo considerado como un "contenedor", mientras que con Monad tiende a ser considerado como "efectos secundarios", pero esos son solo (a veces engañosa) taquigrafías - que es lo mismo de cualquier manera y no realmente nada especial [0].

La característica distintiva de Monad en comparación con otros Functor s es que se puede incrustar el flujo de control en la estructura adicional. La razón por la que puede hacer esto es que, a diferencia de fmap que aplica una sola función plana en toda la estructura, (>>=) inspecciona elementos individuales y construye nueva estructura a partir de eso.

Con un plano Functor, construir una nueva estructura de cada pieza de la estructura original anidaría en cambio el Functor, donde cada capa representa un flujo de punto de control. Obviamente, esto limita la utilidad, ya que el resultado es complicado y tiene un tipo que refleja la estructura del control de flujo utilizado.

"efectos secundarios"

monádica son estructuras que tienen algunas propiedades adicionales [1]:

  • dos efectos secundarios se pueden agrupar en uno (por ejemplo, "hacer X" y "hacer Y "convertirse en" hacer X, luego Y "), y el orden de agrupación no importa siempre que se mantenga el orden de los efectos. existe
  • Un efecto secundario "no hacer nada" (por ejemplo, "hacer X" y "no hacer nada" agrupados es lo mismo que simplemente "hacer X")

La función join es nada más que eso operación de agrupación : Un tipo de mónada anidada como m (m a) describe dos efectos secundarios y el orden en que ocurren, y join los agrupa en un solo efecto secundario.

Por lo tanto, en cuanto a efectos secundarios monádicos, la operación de enlace es una abreviatura de "tomar un valor con efectos secundarios asociados y una función que introduce nuevos efectos secundarios, luego aplicar la función al valor mientras combina el lado efectos para cada uno ".

[0]: Excepto IO. IO es muy especial.

[1]: Si se comparan estas propiedades a las reglas para una instancia de Monoid verá un estrecho paralelismo entre los dos - esto no es una coincidencia, y de hecho es lo que "sólo un monoide en la categoría de endofunctors, ¿cuál es el problema? " línea se refiere a.

+0

Dicho de manera más abstracta, podemos decir que join es el testigo del hecho de que una mónada se cierra bajo la composición endo-functor (agregando una nueva capa de m, como en (m (ma)) en lugar de meramente (ma). Estos dos son del mismo "tipo" de cosas (una mónada), y unirse hace que la relación entre ellos sea concreta. – nomen

5

De la misma página que recuperar esta información join x = x >>= id, con el conocimiento de cómo las bind y id funciones de trabajo que debe ser capaz de averiguar lo que hace join.

+2

Finalmente entiendo esto, pero no fue nada fácil – Casebash

+3

O, algo más intuitivo cuando se piensa en unir en términos de IO, 'join x = do {a <- x; a} ' – javawizard

4

Lo que hace, conceptualmente, se puede determinar simplemente mirando el tipo: Desenrolla o aplana el contenedor/cómputo monádico externo y devuelve los valores monádicos producidos en el mismo.

¿Cómo lo hace realmente esto está determinado por el tipo de mónada se está tratando. Por ejemplo, para la mónada List, 'join' es equivalente a concat.

23

Lo que unir hace ha sido adecuadamente descrito por las otras respuestas hasta ahora, creo. Si estás buscando una comprensión más intuitiva ... si te estás preguntando qué significa "significa" ... desafortunadamente la respuesta variará dependiendo de la mónada en cuestión, específicamente en lo que M (X) "significa "y lo que M (M (X))" significa ".

Si M es la lista de mónadas, entonces M (M (X)) es una lista de listas, y unirse significa "aplanar". Si M es la mónada Maybe, entonces un elemento de M (M (X)) podría ser "Just (Just x)", "Just Nothing", o "Nothing", y join significa colapsar esas estructuras de la manera lógica para "Just x", "Nothing" y "Nothing" respectivamente (similar a la respuesta de camccann de join como combinación de efectos secundarios).

Para mónadas más complicadas, M (M (X)) se convierte en algo muy abstracto y decidir qué M (M (X)) y unir "significar" se vuelve más complicado. En todos los casos, es algo así como el caso de la mónada List, en el sentido de que estás contrayendo dos capas de abstracción de Mónada en una capa, pero el significado va a variar. Para la mónada estatal, la respuesta de Camccann de combinar dos efectos secundarios es explosiva: unirse significa esencialmente combinar dos transiciones de estado sucesivas. La mónada de Continuación rompe especialmente el cerebro, pero la unión matemática es bastante prolija aquí: M (X) corresponde al "doble espacio dual" de X, lo que los matemáticos podrían escribir como X** (continuaciones mismas, es decir, mapas de X-> R donde R es un conjunto de resultados finales, corresponde al espacio doble simple), y la unión corresponde a un mapa extremadamente natural de X**** a X**. El hecho de que las mónadas de continuación satisfagan las leyes de mónada corresponde al hecho matemático de que generalmente no hay mucho sentido para aplicar el operador de espacio dual * más de dos veces.

Pero estoy divagando.

Personalmente trato de resistir el impulso de aplicar una sola analogía a todos los tipos posibles de mónadas; las mónadas son simplemente un concepto demasiado general para ser encasilladas por una sola analogía descriptiva. Lo que significa que la combinación va a variar según la analogía con la que estés trabajando en un momento dado.

1

Mapas de operaciones de vinculación: ma -> (a -> mb) -> mb. En ma y (el primero) mb, tenemos dos m s. Para mi intuición, la comprensión de las operaciones de enlace y monádicas ha llegado a depender, en gran medida, de la comprensión de cómo se combinan esas dos m s (instancias del contexto monádico). Me gusta pensar en la mónada Writer como un ejemplo para comprender join. Writer se puede usar para registrar operaciones. ma tiene un inicio de sesión. (a -> mb) producirá otro inicio de sesión que primero mb. El segundo mb combina ambos registros.

(Y un mal ejemplo a pensar es la mónada Maybe, porque hay Just + Just = Just y Nothing + nada = Nothing (o F # Some y None) son tan poco informativo se pasan por alto el hecho de que algo importante está pasando Puede pensar en Just como una sola condición para proceder y Nothing como una sola bandera para detenerse. Señales similares en el camino, dejadas atrás a medida que avanza el cálculo. (Que es una impresión razonable ya que aparece el Just o el Nothing final) para ser creado desde cero en el último paso de la computación sin transferir nada de los anteriores). Cuando realmente necesitas enfocarte en el combinador ics de Just sy Nothing s en cada ocasión.)

El problema cristalizado para mí en la lectura de Aprender a Haskell de Miran Lipovaca para Great Good !, Capítulo 12, la última sección de Monad Laws. http://learnyouahaskell.com/a-fistful-of-monads#monad-laws, Asociatividad. Este requisito es: "Hacer (ma >>= f) >>= g es como hacer ma >>= (\x -> f x >>= g) [Yo uso ma para m]". Bueno, en ambos lados, el argumento pasa primero al f y luego al g. Entonces, ¿qué quiere decir con "No es fácil ver cómo esos dos son iguales"? ¡No es fácil ver cómo pueden ser diferentes!

La diferencia está en la asociatividad de los join Ings de m s (contextos) - que los bind Ings hacen, además de mapeo. Enlace desenrollar o va alrededor del m para obtener el a al que se aplica f, pero eso no es todo. El primer m (en ma) se mantiene mientras f genera un segundo m (en mb). Entonces bind combina-- join s - ambos m s. La clave para bind es tanto en el join como en el desplegable (map). Y creo que la confusión sobre join es indicativo de fijarse en el aspecto de desenvolver bind --getting la a de ma con el fin de coincidir con la firma del argumento f 's - y con vistas al hecho de que los dos m s (desde ma y luego mb) necesitan reconciliarse. (Desechando los primeros m puede ser la forma adecuada para manejar la situación en algunos casos (tal vez) - pero eso no es cierto en general -. Como se ilustra escritor)

A la izquierda, que bindma a f en primer lugar, a continuación, a g segundo. Entonces el registro será como: ("before f" + "after f") + "after g". A la derecha, mientras que las funciones f y g se aplican en el mismo orden, ahora se unen a g primero. Entonces el registro será como: "before f" + ("after f" + "after g"). Los paréntesis no están en la (s) cadena (s), por lo que el registro es el mismo de cualquier forma y se observa la ley. (Mientras que si el segundo registro hubiera salido como "after f" + "after g" + "before f" - ¡entonces estaríamos en problemas matemáticos!).

Refundición bind como fmap más join para el escritor, obtenemos fmap f ma, donde f:a -> mb, lo que resulta en m(mb). Piense en el primer m en ma como "antes de f". El f se aplica al a dentro del primer m y ahora llega un segundo m (o mb) - dentro del primer m, donde se realiza el mapeo f. Piense en el segundo m en mb como "después de f".m(mb) = ("antes de f" ("después de f" b)). Ahora usamos Unir para colapsar los dos registros, el m s, haciendo un nuevo m. Writer usa un monoide y nosotros lo concatenamos. Otras mónadas combinan contextos de otras formas: obedecen las leyes. Que es tal vez la parte principal de entenderlos.