Этот вопрос по сути является дубликатом Отладка бесконечных циклов в программах на Haskell с помощью GHCi . Автор там решил это вручную, хотя я хотел бы знать другие решения .
(моя особая проблема)
У меня есть код стрелки, который содержит рекурсивный вызов,
testAVFunctor = proc x -> do
y <- errorArrow "good error" -< x
z <- isError -< y
(passError ||| testAVFunctor) -< trace "value of z" z
errorArrow
должен сделать рекурсивный тест AVFunctor не выполненным, поскольку это заставит isError возвращать Left (AVError "good error")
, который, в свою очередь, должен выбрать маршрут passError
и обойти рекурсивный вызов.
Очень странная вещь заключается в том, что вставка «трассирующих» вызовов на популярных сайтах, таких как композиция функций, приводит к тому, что программа выдает конечное количество выходных данных, а затем останавливается. Не то, что я ожидаю от бесконечной задачи расширения. (см. Правку 1)
Я загрузил свой исходный код здесь , если кому-то так интересно.
РЕДАКТИРОВАТЬ 1
Я не смотрел в нужном месте (если вы хотите посмотреть на источник, очевидно, avEither зацикливался). Я получил это путем , скомпилировав двоичный файл и запустив gdb :
- GDB Main
- r (код запуска)
- Ctrl + C (отправить прерывание) . Обратный след будет бесполезен, но то, что вы можете сделать, это нажать
- с (шаг) . Затем, удерживая нажатой клавишу ввода; Вы должны увидеть множество имен методов. Надеюсь, один из них будет узнаваем.
Вы можете скомпилировать с флагом ghc -O0
, чтобы отключить оптимизацию, которая может раскрыть больше имен методов.
РЕДАКТИРОВАТЬ 3
Очевидно, блок proc x -> do
, приведенный выше, заставлял код генерировать комбинаторы, которые вызывали метод подъема AVFunctor.arr
- что-то там должно нарушать лень. Если я переписать функцию верхнего уровня как
testAVFunctor = errorArrow "good error" >>>
isError >>> (passError ||| testAVFunctor)
тогда все отлично работает. Я думаю, пришло время попробовать учиться и использовать garrows (от аспиранта из Беркли).
Мой общий вывод из опыта заключается в том, что отладка ghci может быть неприятной. Например, мне удалось заставить аргумент f
из AVFunctor.arr
отображаться как локальную переменную, но я не могу получить ничего ужасно информативного из него:
> :i f
f :: b -> c -- <no location info>
Пересмотренный исходный код здесь