2009-04-28 26 views
14

Existe-t-il un moyen d'afficher les étapes de réduction dans haskell, c'est-à-dire de suivre les appels de fonction récursifs effectués? Par exemple, chez scheme nous fournit trace-lambda. Y a-t-il une forme équivalente chez Haskell?Afficher les étapes de réduction dans Haskell

+0

Il y a une énorme différence avec Scheme; Haskell est paresseux, donc l'évaluation réelle peut se produire bien après l'appel. – bortzmeyer

Répondre

7

Vous pouvez essayer d'insérer Debug.Trace.trace dans les endroits que vous voulez tracer, mais cela a tendance à (a) produire une sortie extrêmement désordonnée, car votre instruction trace peut appartenir à un thunk qui n'est pas évalué jusqu'à présent loin de l'appel original, et (b) changer le comportement d'exécution de votre programme, si le traçage nécessite d'évaluer des choses qui n'auraient pas été évaluées (pour le moment).

Est-ce pour le débogage? Si oui ...


Hat modifie votre code source pour le traçage de sortie qui peut être consulté après l'exécution. La sortie devrait être assez proche de ce que vous voulez: l'exemple sur leur page d'accueil est

Par exemple, le calcul du programme défectueux

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 

donne le résultat

(8, No match in pattern. 

et les outils de visualisation Hat peuvent être utilisés pour explorer son comportement comme suit:

  • Hat pile

Pour les calculs avortés, soit calculs qui termine par un message d'erreur ou interrompues, pile de chapeau montre dans laquelle la fonction d'appel calcul a été interrompue. Il le fait en montrant une pile virtuelle d'appels de fonction (redexes). Ainsi, chaque appel de fonction affiché sur la pile a provoqué l'appel de la fonction au-dessus. L'évaluation de l'élément de pile supérieur a provoqué l'erreur (ou pendant son évaluation, le calcul a été interrompu). La pile affichée est virtuelle, car elle ne correspond pas à la pile d'exécution réelle. La pile d'exécution réelle permet une évaluation paresseuse alors que la pile virtuelle correspond à une pile qui serait utilisée pour une évaluation (stricte) avide.

En utilisant le même exemple programme ci-dessus, pile chapeau montre

$ 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 
$ 

Ces jours-ci, GHCi (≥ 6.8.1) est également livré avec un débogueur:

$ 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 = [] 

Bien qu'il ne soit pas aussi agréable, il a l'avantage d'être facilement disponible et d'être utilisable sans recompiler votre code.

0

Il y a une réduction du nombre de câlins, si cela peut vous aider? Sinon, pourriez-vous utiliser quelque chose comme le capuchon des câlins pour envelopper votre code, pour obtenir plus de détails sur ce qu'il fait à chaque étape?

0

Rien de ce genre n'est intégré à la norme Haskell.

J'espère que l'interpréteur graphique Helium offrirait quelque chose comme ceci, mais la page Web est silencieuse sur le sujet.

0

Une solution partielle consiste à utiliser vacuum pour visualiser des structures de données.

J'ai vu quelques animations gif de fold, scan et autres, mais je ne peux pas les trouver pour le moment. Je pense que Cale Gibbard a fait les animations.