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
Répondre
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.
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?
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.
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.
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