Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this Haskell code never terminates?

I recently wrote some Haskell code and it never terminates. After I carefully examined my code, the problem boiled down to the following code piece

main :: IO ()
main = print $ let a = 10 in
               let a = a in
               a :: Int

I guess this must have something to do with the laziness of Haskell since the same code terminates in OCaml. However, if I wrote the following code instead

main :: IO ()
main = print $ let a = 10 in
               let b = a in
               b :: Int

the code would have no problem terminating at all. I can't get the reason since in the original code, the two a's should be considered as two different variables. I don't know why the naming of them has anything to do with the semantic of the program.

like image 272
hooray9 Avatar asked Nov 12 '14 21:11

hooray9


Video Answer


1 Answers

The issue is that, unlike OCaml, let bindings in Haskell are recursive by default. So let x = x in ... is equivalent to OCaml's let rec x = x in ... and is a circular definition.

This is why shadowing variable names in Haskell (ie defining a multiple times) is considered bad style and even has a compiler warning, which you can turn on with the -Wall flag or more specifically -fwarn-name-shadowing.

This default makes more sense in Haskell than OCaml because, thanks to laziness, circular values (rather than just recursive functions) are actually useful. let x = 1:x gives us an infinite list of 1, which we can use just like a normal list.

At the same time, some people don't like this for basically exactly the reason you ran into here: it's possible to introduce unintuitive infinite loops in your code, which makes some errors and typos harder to track down. This is also confusing because, by necessity, <- bindings in do-notation are not recursive by default, which is a bit inconsistent.

like image 150
Tikhon Jelvis Avatar answered Sep 28 '22 10:09

Tikhon Jelvis