Pregunta

procedentes de la comunidad Ocaml, estoy tratando de aprender un poco de Haskell. La transición va bastante bien, pero estoy un poco confundido con la depuración. Solía ??poner un montón de () "printf" en mi código ocaml, para inspeccionar algunos valores intermedios, o como bandera para ver donde el cómputo no exactamente.

Desde printf es un IO acción, tengo que levantar todo el código de mi Haskell dentro de la IO mónada que ser capaz de este tipo de depuración? ¿O hay una mejor manera de hacer esto (que realmente no quiero hacerlo a mano si se puede evitar)

También parece que el traza Función: http://www.haskell.org/haskellwiki/Debugging#Printf_and_friends que parece exactamente lo que quiero, pero no entiendo su tipo: no hay IO en cualquier lugar! Alguien me puede explicar el comportamiento de la función de rastreo?

¿Fue útil?

Solución

trace es el más fácil de usar método para la depuración. No está en IO exactamente por la razón que señaló: sin necesidad de levantar el código en la mónada IO. Se implementa de la siguiente

trace :: String -> a -> a
trace string expr = unsafePerformIO $ do
    putTraceMsg string
    return expr

Así que hay detrás de las escenas IO pero unsafePerformIO se utiliza para escapar de ella. Esa es una función que potencialmente rompe la transparencia referencial que se puede adivinar mirando su tipo IO a -> a y también su nombre.

Otros consejos

trace, únicamente se hace impuro. El punto de la mónada IO es preservar la pureza (sin IO inadvertido por el sistema de tipos) y definir el orden de ejecución de los estados, que de otro modo sería prácticamente undefined a través de la evaluación perezosa.

El propio riesgo, sin embargo, puede, sin embargo, cortar a algunos IO a -> a, es decir, realizar impura IO. Este es un truco y por supuesto "sufre" de la evaluación perezosa, pero eso es lo que traza simplemente hace por el bien de la depuración.

Sin embargo, aunque, probablemente debería ir a otras formas de depuración:

  1. Reduciendo la necesidad de depurar los valores intermedios

    • Escribir pequeña, reutilizables funciones genéricas y claras, cuya corrección es obvia.
    • Combinar las piezas correctas para mayores piezas correctas.
    • o probar piezas de forma interactiva.
  2. Uso puntos de interrupción etc. (depuración basada en compilador)

  3. Use mónadas genéricos. Si el código es monádica, sin embargo, escribirlo independiente de una mónada concreto. Uso type M a = ... en lugar de IO ... llanura. Se puede combinar fácilmente después mónadas a través de transformadores y poner una mónada depuración en la parte superior de la misma. Incluso si la necesidad de que las mónadas se ha ido, sólo podría inserción Identity a para los valores puros.

Por lo que vale, en realidad hay dos clases de "depurar" en cuestión aquí:

  • Registro de valores intermedios, tales como el valor de una subexpresión particular tiene en cada llamada en una función recursiva
  • Inspeccionar el comportamiento de tiempo de ejecución de la evaluación de una expresión

En un estricto lenguaje imperativo estos por lo general coinciden. En Haskell, que a menudo no lo hacen:

  • Grabación valores intermedios puede cambiar el comportamiento de tiempo de ejecución, tal como forzando la evaluación de términos que de otro modo serían descartados.
  • El proceso real de cálculo puede diferir drásticamente de la estructura aparente de una expresión debido a la pereza y subexpresiones compartidos.

Si lo que desea es mantener un registro de valores intermedios, hay muchas maneras de hacerlo - por ejemplo, en lugar de levantar todo en IO, un simple mónada Writer será suficiente, lo que equivale a hacer funciones devuelven un 2 tupla de su resultado real y un valor del acumulador (una especie de lista, por lo general).

También es por lo general no es necesario para poner todo en la mónada, sólo las funciones que necesita para escribir en el valor "log" - por ejemplo, se puede factorizar sólo las subexpresiones que necesitan poder hacer el registro, dejando la lógica principal puro, a continuación, volver a montar el cálculo global mediante la combinación de funciones puras y cálculos de registro de la forma habitual con fmaps y otras cosas. Tenga en cuenta que Writer es una especie de mal ejemplo de una mónada: no hay forma de leer de el registro, solamente escribir en él, cada cálculo es lógicamente independiente de su contexto, lo que hace que sea más fácil malabares cosas a su alrededor.

Sin embargo, en algunos casos incluso de que Overkill -. Para muchas funciones puras, simplemente se mueven a la subexpresiones de nivel superior y probar cosas en el REPL funciona bastante bien

Si desea inspeccionar realmente el comportamiento en tiempo de ejecución de código puro, sin embargo - por ejemplo, para averiguar por qué un diverge subexpresión - no es en general no hay manera de hacerlo desde otro código puro - de hecho, esta es esencialmente la em> definición de la pureza <. Así que en ese caso, no tiene más remedio que utilizar las herramientas que existen "fuera" de la lengua pura: o funciones impuras como unsafePerformPrintfDebugging - errr, quiero decir trace - o un entorno de ejecución modificado, tal como el depurador GHCi <. / p>

trace también tiende a evaluar sobre su argumento para la impresión, la pérdida de una gran cantidad de los beneficios de la pereza en el proceso.

Si puede esperar hasta que el programa se termina antes de estudiar la salida, a continuación, el apilamiento de una escritor mónada es el enfoque clásico de la implementación de un registrador. Yo uso este aquí para devolver un resultado fijar de código impura HDBC.

Bueno, ya que Haskell conjunto está construido en torno a principio de la evaluación perezosa (para que el orden de los cálculos es, de hecho, no determinista), el uso de printf de hacer muy poco sentido en ella.

Si REPL + inspeccionar valores resultantes es realmente no es suficiente para su depuración, envolver todo en IO es la única opción (pero no es la forma correcta de programación Haskell).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top