The problem is that, unlike OCaml, let bindings in Haskell are recursive by default. Thus, let x = x in ... equivalent to OCaml let rec x = x in ... and is a circular definition.
That's why shadowing variable names in Haskell (i.e. defining a several times) is considered bad style and even has a compiler warning that you can turn on with the -Wall flag or, more specifically, -fwarn-name-shadowing .
This default value makes more sense in Haskell than OCaml, because laziness makes circular values ββ(and not just recursive functions) really useful. let x = 1:x gives us an infinite list 1 , which we can use as a regular list.
At the same time, some people do not like this mainly for the reason you came across here: it is possible to introduce non-intuitive endless loops into your code, which makes it difficult to track errors and typos. This is also confusing, because if necessary, <- bindings in do-notation are not recursive by default, which is a bit inconsistent.
source share