Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange <<loop>> exception in Array generation

Tags:

haskell

I ran into an infinite loop problem in Haskell and can't understand what the cause is. I have three versions of the same code below. The first one causes an infinite loop while the latter two do not. This is some basic contrived code to generate an array recursively. In this case it has only three items and the only recursive call is for the third item which picks the bigger of the first two. The if a > b statement seems to cause a loop (but later I show that it can't be the cause).

import Data.Array

main :: IO ()
main = print grid
  where grid = array (0, 2) $ map func [0 .. 2]
        func i
            | i == 2 = let a = grid ! (i - 1)
                           b = grid ! (i - 2)
                        in if a > b
                              then (i, a)
                              else (i, b)
            | otherwise = (i, 0)

In the following version, I simply use max a b instead of the if statement. No loop here.

main :: IO ()
main = print grid
  where grid = array (0, 2) $ map func [0 .. 2]
        func i
            | i == 2 = let a = grid ! (i - 1)
                           b = grid ! (i - 2)
                        in (i, max a b)
            | otherwise = (i, 0)

In the following version, I keep the if but zip the indices instead of returning a tuple from func. This one also runs fine.

main :: IO ()
main = print grid
  where grid = array (0, 2) $ zip [0 .. 2] $ map func [0 .. 2]
        func i
            | i == 2 = let a = grid ! (i - 1)
                           b = grid ! (i - 2)
                        in if a > b
                              then a
                              else b
            | otherwise = 0

Those two other cases seem to show that there is no problem with the recursive definition or the use of the if statement.

What does that leave as the cause of the loop?

like image 566
wilywampa Avatar asked May 07 '15 02:05

wilywampa


1 Answers

Here is an interesting observation: in (i, max a b), we know (before computing either a or b) that this tuple has i in its first component. Similarly, in your zip code, we can observe that the first parts of the tuples are 0, 1, and 2 without computing the second parts of the tuples. However, in if a > b then (i, a) else (i, b), it is not obvious that we have a tuple with i in the first part: if a > b is bottom, for example, then the result of this expression is bottom, not a tuple with i in the first part!

This matters because computing a > b requires computing a, which requires knowing which value is in position 0 in the array, which requires knowing whether i is 0 in the last element of the mapped list (and hence should overwrite the previous 0 value) -- a loop.

One fix is to lift the (i, _) part out of the if, and use (i, if a > b then a else b). This is essentially what your max solution does.

like image 141
Daniel Wagner Avatar answered Oct 21 '22 00:10

Daniel Wagner