Бесконечная рекурсия в Хаскеле
Этот вопрос по сути является дубликатом отладки бесконечных циклов в программах на 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)
тогда все работает нормально. Я думаю, пришло время попробовать учиться и использовать бороны (от аспиранта здесь, в Беркли).
Мой общий вывод из опыта состоит в том, что отладка ghci может быть расстраивающей. Например, мне удалось привести аргумент f
из AVFunctor.arr
показываться как локальная переменная, но я не могу получить от нее ничего ужасно информативного:
> :i f
f :: b -> c -- <no location info>
Пересмотренный исходный код здесь
1 ответ
Имейте в виду, что значение (|||)
зависит от стрелки и testAVFunctor
бесконечный объект вашей стрелы:
testAVFunctor = proc x -> do
...
(passError ||| proc x -> do
...
(passError ||| proc x -> ...) -< trace "value of z" z)
-< trace "value of z" z
Я не уверен, что вы знали об этом. Изучите определение (|||)
(или если его нет, left
), чтобы увидеть, если он может обрабатывать бесконечные условия. Также проверьте (>>>)
(Эр, (.)
в современных версиях я думаю). Убедитесь, что комбинаторы не являются строгими, потому что тогда бесконечный термин будет расходиться. Это может включать создание более ленивых шаблонов ~
(Мне приходилось делать это много при работе со стрелками). Поведение, которое вы видите, может быть вызвано слишком большой строгостью в одном из комбинаторов, поэтому он оценивает "достаточно далеко", чтобы дать некоторый результат, но затем застревает позже.
Удачи. Вы в глубине тонкости Хаскелла.