The key thing about lazy evaluation in Haskell is that it does not affect the output of your program at all. You can read it as if everything was evaluated as soon as it is determined, and you will still get the same result.
Lazy evaluation is simply a strategy for determining the meaning of an expression in a program. There are many of them, and all of them give the same result [1]; any evaluation strategy that changes the meaning of the program will not be a valid strategy!
So, from a certain point of view, you do not need to sort out a lazy assessment (for now) if this gives you problems. When you learn Haskell, especially if this is your first functional and clean language, thinking about how to express yourself in this way is much more important. I would also appreciate learning on my own to make it comfortable to read the Haskell (often quite dense) syntax as more important than a completely grokking lazy grade. Therefore, do not worry too much if the concept gives you difficulties.
However, I will explain it below. I did not use your examples, because they were not affected by a lazy assessment, and Owen spoke more clearly than I could about dynamic binding and delayed execution according to your example.
The most important difference between (valid) evaluation strategies is that some strategies may not return at all, where another strategy may be successful. Lazy evaluation has a special property, which if any (real) evaluation strategy can find a result, a lazy rating will find it. In particular, programs that generate endless data structures and then use only a finite amount of data can end with a lazy assessment. In a rigorous evaluation, which you are probably accustomed to, the program must complete the creation of an infinite data structure before it can continue to use part of it, and, of course, it will.
Lazy assessment achieves this by only evaluating something when you need to figure out what to do next. When you call a function that returns a list, it "returns immediately" and gives you a placeholder for the list. This placeholder can be passed to other functions stored in other data structures, whatever. Only when the program needs to know something about the list will it be actually evaluated and only as necessary.
Say that now the program will do something different if the list is empty than if it weren’t. The function call that the placeholder originally returned is evaluated a little further to see if it returns an empty list or a list with a title element. Then the evaluation stops again, as the program now knows where to go. If the rest of the list is never needed, it will never be rated.
But he was also not evaluated more than once. If a placeholder has been passed into several functions (so that it is now involved in other not yet evaluated functions calls) or stored in several different data structures, Haskell still “knows” that they are all the same, and will arrange everything for them to “see” the consequences of any further placeholder evaluation caused by any of them. In the end, if the whole list is needed somewhere, they will all point to the usual fully evaluated data structure, and laziness does not have a further effect.
But it’s important to remember that everything needed to create this list is already defined and fixed when creating the placeholder. He cannot work on anything else that has happened in the program since then. If this were not so, then Haskell would not be clean . And vice versa; in unclean languages there cannot be total laziness in the Haskell style, because the results you get can change a lot depending on when you need the results in the future . Instead, unclean languages that support lazy evaluation tend to have it only for certain things explicitly stated by the programmer, with warnings in the manual that say, "Don't use laziness on something that depends on side effects."
[1] I am lying a little here. Continue reading below line to understand why.