Бесконечная рекурсия в Хаскеле - PullRequest
5 голосов
/ 01 мая 2011

Этот вопрос по сути является дубликатом Отладка бесконечных циклов в программах на 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>

Пересмотренный исходный код здесь

1 Ответ

3 голосов
/ 01 мая 2011

Имейте в виду, что значение (|||) зависит от стрелки, а testAVFunctor является бесконечным объектом вашей стрелки:

testAVFunctor = proc x -> do
    ...
    (passError ||| proc x -> do
                       ...
                       (passError ||| proc x -> ...) -< trace "value of z" z)
        -< trace "value of z" z

Я не уверен, знали ли вы об этом. Изучите определение (|||) (или, если его нет, left), чтобы увидеть, может ли оно обрабатывать бесконечные термины. Также проверьте (>>>) (э-э, (.) в современных версиях, я думаю). Убедитесь, что комбинаторы не являются строгими, потому что тогда бесконечный термин будет расходиться. Это может включать в себя создание более ленивых шаблонов с ~ (мне приходилось делать это много при работе со стрелками). Поведение, которое вы видите, может быть вызвано слишком большой строгостью в одном из комбинаторов, поэтому он оценивает «достаточно далеко», чтобы дать какой-то вывод, но затем застревает позже.

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

...