Abstractly your program is a tree rooted at main. In a language like C you concentrate on building trees knowing that you are going to touch every node. So you are trying to design small trees that have good execution semantics as well as being correct in the problem solving domain. You have to address the problem at 2 levels. Because C is strict every function you call will be evaluated before it can return some result.
Haskell is different you can build any tree you like because a node will only be evaluated if its result is required for the current context. You are free to work with models of data like "the integers" or "all possible game states".
Concretely in C if you wanted to find the smallest positive integer that satisfies some property P you would write something like
for (int i=1; ; i++) if (P(i)) return i;
This is a single node in your program tree which modifies a variable until a condition is met.In contrast in Haskell you might do something like
find P [1..]
I would interpret this as find operating on an infinite lazy tree and discarding the infinite tail list (which is an infinite computation) once the result is found.Applying this simple example, in Haskell you aren't concern with limiting the shape of your program's tree. You build the correct model for your program regardless of constraints like infinite lists or terminating searches early. You just allow non-strict evaluation to process your input data because you will never have to strictly generate an infinite integer list before scanning it.
At root non-strict semantics is just a reversal of the order of reduction of expressions.