3

I could not figure out in my code what function is raising (*** Exception: Prelude.!!: negative index since this exception is not very descriptive about the error. Is there any way to detect exactly what custom function is calling !! and raising this error.

This is a simple reproducible example of the error when is called index_around 0 [1, 2, 3], here the exception text doesn't describe if the exception is raised by index_before or by index_after function.

index_before :: Int -> [a] -> a
index_before i list = list !! (i - 1)

index_after :: Int -> [a] -> a
index_after i list = list !! (i + 1)

index_around :: Int -> [a] -> (a, a)
index_around i list = (index_before i list, index_after i list)
svex99
  • 518
  • 4
  • 10

2 Answers2

5

There are a few methods you can use to debug haskell code:

  • Using Debug.Trace which logs messages to stderr wherever you use the trace function. It requires modification of your code, and since trace is an impure function (which hides IO using unsafePerformIO), you should use it with caution.
  • Using the -xc RTS flag after compiling with -prof -fprof-auto, which gives you the exact call stack when an exception is raised.
  • Using the GHCi debugger. A good example of how to use it can be found here.
Vikstapolis
  • 744
  • 3
  • 13
1

When you call index_around 0 [1, 2, 3], you're calling index_before (-1) [1, 2, 3] and index_after 1 [1, 2, 3].

-1 is a negative index.

You may wish to do some bounds checking, and employ the Maybe type. This way the exception never happens.

index_around :: Int -> [a] -> (Maybe a, Maybe a)
index_around n lst 
    | length lst == 0 = (Nothing, Nothing)
    | n == 0          = (Nothing, Just $ index_after n lst)
    | n == length lst = (Just $ index_before n lst, Nothing)
    | otherwise       = (Just ib, Just ia) 
          where ib = index_before n lst
                ia = index_after n lst
Chris
  • 26,361
  • 5
  • 21
  • 42
  • 5
    Yes, in the example is obvious, but when you have a main entry point and a lot of functions that calls `!!` is hard to detect which of your functions is raising the error. The objective of the question is to get programmatically exactly what function raises the exception, since the exception description is not very informative. Get a traceback will be great. – svex99 Feb 04 '22 at 16:39