Бесконечная рекурсия в Хаскеле

Этот вопрос по сути является дубликатом отладки бесконечных циклов в программах на 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), чтобы увидеть, если он может обрабатывать бесконечные условия. Также проверьте (>>>) (Эр, (.) в современных версиях я думаю). Убедитесь, что комбинаторы не являются строгими, потому что тогда бесконечный термин будет расходиться. Это может включать создание более ленивых шаблонов ~ (Мне приходилось делать это много при работе со стрелками). Поведение, которое вы видите, может быть вызвано слишком большой строгостью в одном из комбинаторов, поэтому он оценивает "достаточно далеко", чтобы дать некоторый результат, но затем застревает позже.

Удачи. Вы в глубине тонкости Хаскелла.

Другие вопросы по тегам