0
votes

I'm newbie to Haskell and write the following small code but it failed with loop exception. The problem is the code doesn't use the loop , even recursion. That's make me crazy!

gameList :: [Int]->Int->Int->[(Int, Int)]
gameList  org pos step =
    let next  = (mod (pos + step)  2) ;
        pos = next;             
    in  [(pos, pos)]

Then save it in one file and succeed to load it into GHC with interactive mode. invoke it like this gameList [1,2,3] 0 1

It will throw error "[(*** Exception: <>"

The GHCI info :WinGHCi 1.0.6 Help me!

2
Infinite loop here because pos is one of your arguments. What are you trying to do? What is the expected output of gameList [1,2,3] 0 1? - shree.pat18
BTW, you normally never need to end lines with semicolons in Haskell, nor do you need to surround definitions with parentheses. - leftaroundabout
The reason is that let expression is not assignment, it's defintion of block code. In this case, it's recursive. The same case as the following code: let t = (let pos = next; next = pos in (pos, next)) - RocZhang

2 Answers

4
votes

"doesn't use a loop, even recursion"

I'm afraid it does actually use recursion, albeit in a way that isn't even possible in non-lazy languages!

The crux is that your parameter pos is never actually used anywhere, it's immediately shadowed by the pos defined in the let block (GHC would have warned you about that, with -Wall!). So your code is equivalent to

gameList org _ step =
    let next  = (mod (pos + step)  2) ;
        pos = next;             
    in  [(pos, pos)]

where next is defined in terms of pos which is defined in terms of next which is... and so on.

The obvious fix is to remove the line pos = next, which is completely unnecessary anyway.

gameList org pos step
  = let next  = (pos + step) `mod` 2
    in  [(next, next)]
2
votes

doesn't use the loop , even recursion

This is not correct, here's why.

gameList :: [Int]->Int->Int->[(Int, Int)]
gameList  org pos step =              -- this is an unused argument named pos
  let next  = (mod (pos + step)  2) ; -- here we define next in terms of pos
        pos = next;                   -- ... which is defined here in terms of next
    in  [(pos, pos)]                  -- here we use this circularly-defined pos

See, let is not an assignment, and it is not "executed" top-to-bottom. let introduces a block of mutually-recursive definitions. So this

let next  = (mod (pos + step)  2) ;
    pos = next;             

does not use pos the function argument at all.