I'm of the opinion that laziness is the single hardest thing to get used to in Haskell: not warm fuzzy things, not higher order functions, not syntax. The reason why it's taken me awhile, having used Haskell more off than on for small toys over the past couple of years, to really grasp how to use lazy evaluation is that it forces you to think about the combination of your functions and data much more carefully.
Let's take a really silly example such asbecause it's something that is easy & obvious. If you apply this function to a list of numbers the evaluation can proceed something like the following:
head . map (+1)
head . map (+1) [1,2,..]To anyone remotely familiar with the concept of laziness I'm sure this seems somewhat intuitive. You only need the first element of the list, so only the first element has the argument to map applied to it. It's a simple consequence of the structure of lists and the definition of map, the kind of example that you can feel comfortable with after just a minute with a pencil and paper. So what's my point?
head $ ((+1) 1):(map (+1) [2,...])
My point is that if you're learning Haskell and you're running into problems with laziness, you should break out the pencil & paper and try to calculate what will happen when your function is called. It's something you don't really have to do with other languages, but I think it's the best way to see how your functions and data structures interact during evaluation until you have better intuition.