Посмотреть шаги по сокращению в Haskell
Есть ли способ просмотреть шаги сокращения в haskell, то есть отследить выполненные рекурсивные вызовы функций? Например, схема chez предоставляет нам trace-lambda. Есть ли эквивалентная форма в Haskell?
4 ответа
Вы можете попробовать вставить Debug.Trace.trace
в местах, которые вы хотите отследить, но это имеет тенденцию к (a) получению дико нестандартных выходных данных, так как ваш оператор трассировки может принадлежать thunk, который не оценивается, пока далеко от исходного вызова, и (б) изменение поведения вашей программы во время выполнения, если трассировка требует оценки вещей, которые иначе не были бы оценены (пока).
Это для отладки? Если так...
Hat изменяет ваш исходный код для вывода трассировки, которую можно просмотреть после запуска. Вывод должен быть очень близок к тому, что вы хотите: пример на их домашней странице
Например, вычисление неисправной программы
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
дает результат
(8, No match in pattern.
и инструменты просмотра Hat можно использовать для изучения его поведения следующим образом:
- Хет-стек
Для прерванных вычислений, то есть вычислений, которые завершились сообщением об ошибке или были прерваны, hat-stack показывает, в каком вызове функции вычисление было прервано. Это достигается путем показа виртуального стека вызовов функций (переопределений). Таким образом, каждый вызов функции, показанный в стеке, вызывал вызов функции над ним. Оценка верхнего элемента стека вызвала ошибку (или во время его вычисления вычисление было прервано). Показанный стек является виртуальным, поскольку он не соответствует фактическому стеку времени выполнения. Фактический стек времени выполнения позволяет выполнять отложенную оценку, тогда как виртуальный стек соответствует стеку, который будет использоваться для активной (строгой) оценки.
Используя ту же программу примера, что и выше, hat-stack показывает
$ 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 $
В наши дни GHCi (≥6.8.1) также поставляется с отладчиком:
$ 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 = []
Хотя это не так приятно, оно имеет преимущество в том, что оно легко доступно и может быть использовано без перекомпиляции кода.
Есть сокращение количества объятий, если это помогает? В качестве альтернативы, вы могли бы использовать что-то вроде капюшона объятий, чтобы обернуть ваш код, чтобы получить более подробную информацию о том, что он делает на каждом этапе?
Частичным решением является использование вакуума для визуализации структур данных.
Я видел некоторые gif-анимации складывания, сканирования и другие, но пока не могу их найти. Я думаю, что Кейл Гиббард сделал анимацию.
Ничего подобного не встроено в стандарт Haskell.
Я надеюсь, что графический интерпретатор Helium предложит что-то подобное, но на веб-странице ничего не говорится об этой теме.