5

This question is essentially a duplicate of Debugging infinite loops in Haskell programs with GHCi. The author there solved it manually, though I'd like to know other solutions.

(my particular problem)

I have an arrow code which contains a recursive invocation,

testAVFunctor = proc x -> do
    y <- errorArrow "good error" -< x
    z <- isError -< y
    (passError ||| testAVFunctor) -< trace "value of z" z

The errorArrow should make the recursive testAVFunctor not execute, since that will cause isError to return a Left (AVError "good error") which should in turn choose the passError route and bypass the recursive call.

The very odd thing is that inserting "trace" calls at popular sites like the function composition results in the program emitting a finite amount of output, then freezing. Not what I'd expect from an infinite term expansion problem. (see edit 1)

I've uploaded my source code here if anyone is so curious.

EDIT 1

I wasn't looking in the right place (if you care to look at the source, apparently avEither was looping). The way I got there was by compiling a binary, and running gdb:

  • gdb Main
  • r (runs code)
  • Ctrl+C (send interrupt). The backtrace will be useless, but what you can do, is hit
  • s (step). Then, hold down the enter key; you should see a lot of method names fly by. Hopefully one of them will be recognizable.

You can compile with ghc flag -O0 to disable optimization, which can reveal more method names.

EDIT 3

Apparently, the proc x -> do block above was causing the code to generate combinators, which were calling the AVFunctor.arr lifting method to be called -- something in there must be violating laziness. If I rewrite the top level function as

testAVFunctor = errorArrow "good error" >>>
    isError >>> (passError ||| testAVFunctor)

then everything works fine. I guess it's time to try learning and using garrows (by a grad student here at Berkeley).

My general takeaway from the experience is that ghci debugging can be frustrating. For example, I managed to make the argument f of AVFunctor.arr show up as a local variable, but I can't get anything terribly informative from it:

> :i f
f :: b -> c     -- <no location info>

Revised source code is here

Community
  • 1
  • 1
gatoatigrado
  • 16,580
  • 18
  • 81
  • 143
  • On the duplicate question linked, the author solved it manually, and other users commenting there had asked for the source. So, I started this question. I am certainly debugging it and will update this page as I find out more. If anyone knows automatic techniques though, I would much appreciate it -- I am a haskell newbie. – gatoatigrado May 01 '11 at 06:24
  • Huh, I thought gdb didn't work with ghc based on http://hackage.haskell.org/trac/ghc/wiki/Debugging/CompiledCode?redirectedfrom=DebuggingGhcCrashes – Adam May 02 '11 at 00:16
  • You don't see a real stack trace, but you can see some method names. For this example, download the original AVFunctor.zip (link before the edit sections), then run `ghc -O0 --make Main.hs`, then `gdb Main`, and `r`, `ctrl+c`, and `s` as above. You'll see something that looks like this, http://pastebin.com/xSJ9uMn3 . – gatoatigrado May 02 '11 at 01:15

1 Answers1

3

Keep in mind that the meaning of (|||) depends on the arrow, and testAVFunctor is an infinite object of your arrow:

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

I'm not sure if you were aware of that. Examine the definition of (|||) (or if there isn't one, left) to see if it can handle infinite terms. Also check (>>>) (er, (.) in modern versions I think). Make sure the combinators are not strict, because then an infinite term will diverge. This may involve making patterns lazier with ~ (I have had to do this a lot when working with arrows). The behavior you're seeing might be caused by too much strictness in one of the combinators, so it evaluates "far enough" to give some output but then gets stuck later.

Good luck. You're into the deep subtleness of Haskell.

luqui
  • 59,485
  • 12
  • 145
  • 204
  • Thanks, I'll need it :). I am in the process of checking (|||); it's likely somewhere in there. I had some luck with ~ on a simpler example, thanks! – gatoatigrado May 01 '11 at 06:19