30 votos

¿Cómo funciona ArrowLoop? ¿También, mfix?

Me siento bastante cómodo ahora con el resto de la flecha de la maquinaria, pero no entiendo cómo bucle de obras. Parece mágico para mí, y lo que es malo para mi entendimiento. También tengo problemas para entender mfix. Cuando miro a una pieza de código que utiliza rec en proc o do bloque, me confundo. Con regular monádico o flecha código, puedo paso a través de la computación y mantener una imagen operacional de lo que está pasando en mi cabeza. Cuando llego a rec, no sé qué imagen a seguir! Me quedo atascado, y no veo la razón acerca de dicho código.

El ejemplo, estoy tratando de asimilar es de Ross Paterson papel en flechas, uno sobre los circuitos.

counter :: ArrowCircuit a => a Bool Int
counter = proc reset -> do
        rec     output <- returnA -< if reset then 0 else next
                next <- delay 0 -< output+1
        returnA -< output

Supongo que si entiendo este ejemplo, voy a ser capaz de entender bucle en general, y se va un gran camino hacia la comprensión de mfix. Se sienten esencialmente el mismo para mí, pero tal vez no es una sutileza que me falta? De todos modos, lo que yo realmente premio es una operativa imagen de esas piezas de código, así que puedo paso a través de ellos en mi cabeza como 'regular' código.

Edit: Gracias a Pigworker la respuesta, he comenzado a pensar acerca de rec y como exige ser cumplida. Tomando la counter ejemplo, la primera línea de la rec bloque de demanda de un valor llamado output. Me imagino que esto operacionalmente como la creación de un cuadro, calificándola output, y pidiendo que el rec bloque para llenar la caja. Con el fin de llenar ese cuadro, se ingresa un valor para returnA, pero ese valor en sí exige otro valor, llamado next. Con el fin de utilizar este valor, que debe ser exigido de otra línea en la rec bloque pero no importa donde en el rec bloque se exige, por ahora.

Así que ir a la siguiente línea, y nos encontramos con la caja etiquetada next, y exigimos que otro cálculo que se llene. Ahora, este cálculo se exige nuestra primera caja! Así que nos dan el cuadro, pero no tiene ningún valor en su interior, por lo que si este cálculo se exige que el contenido de output, llegamos a un bucle infinito. Afortunadamente, el retraso que lleva la caja, pero produce un valor sin mirar dentro de la caja. Esta llena de next, que luego nos permite rellenar output. Ahora que output está llena, cuando la próxima entrada de este circuito es procesado, la anterior output caja tendrá su valor, listo para ser demandada en orden a la producción de la próxima next, y por lo tanto la próxima output.

¿Cómo suena?

25voto

pigworker Puntos 20324

En este código, la pieza clave es el delay 0 flecha en la rec bloque. Para ver cómo funciona, ayuda a pensar en valores que varían con el tiempo y la hora picado en rodajas. Creo que de los cortes como 'días'. El rec bloque se explica cómo cada día de cálculo de works. Es organizado por valor, en lugar de por la causal de orden, pero podemos seguir la pista de la causalidad, si somos cuidadosos. Fundamentalmente, debemos asegurarnos de que (sin ayuda alguna de los tipos) que cada día de trabajo se basa en el pasado pero no el futuro. El uno-día delay 0 nos compre momento en que el respeto: cambia su señal de entrada un día más tarde, teniendo cuidado de que el primer día, dando el valor 0. El retraso de la señal de entrada es 'mañana, next'.

rec     output <- returnA -< if reset then 0 else next
        next <- delay 0 -< output+1

Por lo tanto, viendo las flechas y sus resultados, estamos ofreciendo a los de hoy en día output , pero la de mañana, next. Busca en las entradas, dependemos de hoy en día reset y next valores. Es claro que podemos entregar los resultados de esas entradas sin viajes en el tiempo. El output es hoy en día next número a menos que reset a 0; el día de mañana, el next número es el sucesor de la actual output. Hoy en día next valor por lo tanto viene de ayer, a menos que no hubo ayer, en cuyo caso es 0.

En un nivel inferior, esta configuración funciona porque de Haskell pereza. Haskell calcula por la demanda, de estrategia, de modo que si hay un orden secuencial de las tareas que respeta la causalidad, Haskell va a encontrar. Aquí, el delay establece dicha orden.

Ser conscientes, sin embargo, que Haskell del tipo de sistema le da muy poco de ayuda en asegurar que existe tal documento. Eres libre de utilizar bucles para un completo disparate! Así que tu pregunta está lejos de ser trivial. Cada vez que lea o escriba un programa como tal, necesita pensar '¿cómo puede posiblemente este trabajo?". Usted necesita comprobar que delay (o similar) se usa de manera apropiada para garantizar que la información que se exige sólo cuando se puede ser calculada. Tenga en cuenta que los constructores, especialmente, (:) puede actuar como retrasos, demasiado: no es inusual para el cálculo de la cola de una lista, al parecer, dada la totalidad de la lista (pero con cuidado de inspección de la cabeza). A diferencia de la programación imperativa, el perezoso de estilo funcional permite organizar el código en torno a conceptos distintos de la secuencia de eventos, pero es una libertad que exige una más sutiles de la conciencia del tiempo.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X