2009-04-28 17 views
14

¿Hay alguna manera de ver los pasos de reducción en haskell, es decir, rastrear las llamadas a la función recursiva realizadas? Por ejemplo, el esquema Chez nos proporciona trace-lambda. ¿Hay una forma equivalente en Haskell?Ver Pasos de reducción en Haskell

+0

Hay una gran diferencia con Scheme; Haskell es flojo, por lo que la evaluación real puede ocurrir mucho después de la llamada. – bortzmeyer

Respuesta

7

Puede intentar insertar Debug.Trace.trace en los lugares que desea rastrear, pero esto tiene la tendencia de (a) producir resultados descabellados fuera de orden, ya que su instrucción de rastreo puede pertenecer a un procesador que no se evalúa hasta ahora muy lejos de la llamada original, y (b) cambiando el comportamiento del tiempo de ejecución de su programa, si el rastreo requiere evaluar cosas que de otro modo no se hubieran evaluado (aún).

¿Esto es para la depuración? Si es así ...


Hat modifica el código fuente para el rastreo de salida que se puede ver después de correr. La salida debe ser bastante cerca de lo que quiere: el ejemplo en su página web es

Por ejemplo, el cálculo del programa defectuoso

main = let xs :: [Int] 
      xs = [4*2,5 `div` 0,5+6] 
     in print (head xs,last' xs) 

last' (x:xs) = last' xs 
last' [x] = x 

da el resultado

(8, No match in pattern. 

y las herramientas del sombrero de visualización se pueden utilizar para explorar su comportamiento de la siguiente manera:

  • Hat-pila

para cálculos abortados, es decir cálculos que termina con un mensaje de error o interrumpidas, hat-pila muestra en la que la función de llamada el cálculo fue abortado. Lo hace al mostrar una pila virtual de llamadas a función (redexas). Por lo tanto, cada llamada de función que se muestra en la pila provocó la llamada a la función que está sobre ella. La evaluación del elemento de pila superior provocó el error (o durante su evaluación se interrumpió el cálculo). La pila que se muestra es virtual, porque no se corresponde con la pila de tiempo de ejecución real. La pila de tiempo de ejecución real permite la evaluación diferida, mientras que la pila virtual corresponde a una pila que se usaría para una evaluación (estricta) ansiosa.

Usando el mismo programa de ejemplo que el anterior, hat-pila muestra

$ hat-stack Example 
Program terminated with error: 
     No match in pattern. 
Virtual stack trace: 
(Last.hs:6)  last' [] 
(Last.hs:6)  last' [_] 
(Last.hs:6)  last' [_,_] 
(Last.hs:4)  last' [8,_,_] 
(unknown)  main 
$ 

Estos días, GHCi (≥ 6.8.1) también viene con un depurador:

$ ghci -fbreak-on-exception 
GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help 
Loading package ghc-prim ... linking ... done. 
Loading package integer ... linking ... done. 
Loading package base ... linking ... done. 
Prelude> :l Example.hs 
[1 of 1] Compiling Main    (Example.hs, interpreted) 

Example.hs:5:0: 
    Warning: Pattern match(es) are overlapped 
      In the definition of `last'': last' [x] = ... 
Ok, modules loaded: Main. 
*Main> :trace main 
(8,Stopped at <exception thrown> 
_exception :: e = _ 
[<exception thrown>] *Main> :back 
Logged breakpoint at Example.hs:(5,0)-(6,12) 
_result :: t 
[-1: Example.hs:(5,0)-(6,12)] *Main> :hist 
-1 : last' (Example.hs:(5,0)-(6,12)) 
-2 : last' (Example.hs:5:15-22) 
-3 : last' (Example.hs:(5,0)-(6,12)) 
-4 : last' (Example.hs:5:15-22) 
-5 : last' (Example.hs:(5,0)-(6,12)) 
-6 : last' (Example.hs:5:15-22) 
-7 : last' (Example.hs:(5,0)-(6,12)) 
-8 : main (Example.hs:3:25-32) 
-9 : main (Example.hs:2:17-19) 
-10 : main (Example.hs:2:16-34) 
-11 : main (Example.hs:3:17-23) 
-12 : main (Example.hs:3:10-33) 
<end of history> 
[-1: Example.hs:(5,0)-(6,12)] *Main> :force _result 
*** Exception: Example.hs:(5,0)-(6,12): Non-exhaustive patterns in function last' 

[-1: Example.hs:(5,0)-(6,12)] *Main> :back 
Logged breakpoint at Example.hs:5:15-22 
_result :: t 
xs :: [t] 
[-2: Example.hs:5:15-22] *Main> :force xs 
xs = [] 

Aunque no es tan agradable, tiene la ventaja de estar fácilmente disponible y ser utilizable sin volver a compilar el código.

0

¿Hay una reducción en los abrazos, si eso ayuda? Como alternativa, ¿podría usar algo como la capucha de abrazos para envolver su código, para obtener más detalles sobre lo que está haciendo en cada paso?

0

Nada del tipo está integrado en el estándar Haskell.

Espero que el intérprete gráfico Helium ofrezca algo como esto, pero la página web no menciona el tema.

0

Una solución parcial es usar vacuum para visualizar estructuras de datos.

He visto algunas animaciones gif de doblar, escanear y otras, pero no las puedo encontrar en este momento. Creo que Cale Gibbard hizo las animaciones.