Por lo que vale la pena, en realidad hay dos tipos de "depuración" en cuestión aquí:
- Registro de valores intermedios, tales como el valor de una subexpresión en particular tiene en cada llamada a una función recursiva
- Inspección del comportamiento en tiempo de ejecución de la evaluación de una expresión
En un lenguaje imperativo estricto, estos suelen coincidir. En Haskell, a menudo no:
- La grabación de valores intermedios puede cambiar el comportamiento del tiempo de ejecución, forzando la evaluación de los términos que, de lo contrario, se descartarían.
- El proceso real de computación puede diferir dramáticamente de la estructura aparente de una expresión debido a la pereza y las subexpresiones compartidas.
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
, será suficiente un simple Writer
mónada, lo que equivale a hacer funciones devuelve una 2-tupla de su resultado real y un valor de acumulador (una especie de lista, por lo general).
Tampoco es generalmente necesario poner todo en la mónada, sólo las funciones que necesita para escribir en el valor de "log" - por ejemplo, se puede factorizar sólo las subexpresiones que podrían necesitar para hacer conexiones, dejando pura la lógica principal, luego vuelva a ensamblar el cálculo global combinando funciones puras y cálculos de registro de la manera habitual con fmap
sy otras cosas. Tenga en cuenta que Writer
es una excusa lamentable para una mónada: sin forma de leer desde el registro, solo escribir en él, cada cálculo es lógicamente independiente de su contexto, lo que hace que sea más fácil hacer malabares con las cosas.
Pero en algunos casos, incluso eso es exagerado: para muchas funciones puras, simplemente mover subexpresiones al nivel superior y probar cosas en el REPL funciona bastante bien.
Si realmente desea inspeccionar el comportamiento en tiempo de ejecución de código puro, sin embargo, por ejemplo, para descubrir por qué una subexpresión diverge, en general, no hay forma de hacerlo desde otro código puro - de hecho, esta es esencialmente la definición de pureza. Entonces, en ese caso, no tiene más remedio que usar herramientas que existen "fuera" del lenguaje puro: funciones impuras como unsafePerformPrintfDebugging
--errr, quiero decir trace
--o un entorno de tiempo de ejecución modificado, como el depurador GHCi.
Se debe tener en cuenta que 'trace' solo se utiliza para la depuración, y la comunidad lo rechaza si lo usa para la lógica" real ". – luqui