Functional programming languages are either strict or lazy. Strict languages evaluate all arguments to a function before calling it. Lazy languages don’t evaluate arguments until necessary, which may be never. Strict languages evaluate arguments just-in-case, lazy languages evaluate them just-in-time.
Lazy languages are called lazy because they avoid doing work. Or rather they avoid doing unnecessary work. People who avoid doing unnecessary work are sometimes called lazy, too, though unfairly so. In both cases, the term “lazy” can be misleading.
Imagine two computers, L and S. L is running a queue of lazy programs and S a queue of strict programs. L may do less work per program by avoiding pointless calculations. But it may accomplish more productive work than S because the time it saves executing each individual program is used to start running the next program sooner. In this case the lazy computer is getting more productive work done. It seems unfair to call the computer that’s accomplishing more the “lazy” computer. This also could apply to people. Sometimes the people who don’t appear to be working so hard are the ones who accomplish more.
A person who approaches life like a strict programming language is not very smart, and even lazy in the sense of not exercising judgment. Conversely, someone who bypasses an unnecessary task to move on to necessary one, maybe one more difficult than the one skipped over, should hardly be called lazy.
OK, so I like Haskell. By coincidence, I’m actually currently doing stuff using it. But I also program in strict languages, which, by the way, also support various forms of laziness (more and more languages do that through standard libraries or built-in constructs, e.g., OCaml, Scala, Clojure, Python).
But I think your analogy is one-sided. There are drawbacks of laziness. One is that if you have to do something anyway, and know it, then it is more expensive to be lazy, because of the bookkeeping and context switching. Furthermore, if there are side effects (whether in the form of sequential mutation or worse, concurrent), then weird things can happen that you don’t expect.
So I think there is a place for both techniques for dealing with what comes up in life. Sometimes I deal with an email as soon as I get it. Other times I put it aside for later. It’s good to have the choice to do either.
Franklin: Good points. Your comment makes a necessary complementary argument.
I suppose my argument is one-sided because I’m reacting to my frustration with people who have a bias for strictness, folks who focus on formalities rather than on accomplishing goals.
I am familiar with the “formalities” involving types and semantics. I would say that the people who are focused on them have different goals from those who are focused on other things. I think there is a mistake in assuming that people have the same goals; this is a mistake made both in politics and in academia. People actually do have different values and goals, and many kinds of disagreements result from that rather than from a misunderstanding of facts. This is why, for example, “fact checking” does not help much in political debates.
Franklin, I think that’s a good argument illustrating the metaphor. Algorithms do have different purposes and goals, and many bugs and shortcomings result from that rather than from a lack of explicitness. This is why, for example, “type checking” does not help much when you’ve implemented the wrong data structure.
I would characterize things differently (at least as far as language implementation).
Short form “what is ‘work’?”
Long form:
In a lazy language, we are doing extra work to decide what should be done, and when. In a strict language we do not do that work and instead do the work specified by the programmer.
This is a classic design tradeoff. Which approach is better can depend on the programmer, on the application, on how the algorithms are specified, on how we want to think about the problem, and on other such issues.
But the issue is too abstracted from the individual problems for this to be a clear universal “better” or “worse”. Both have advantages. Both allow for clear specification of details.
Anyways, when dealing with resource use, benchmarking often is the best approach for finding the best of several alternatives. Benchmarking also has notorious problems (sometimes people benchmark the wrong things), but when done right it can give proper weight to important issues.
There is a tradeoff to doing things with the lazy approach in programming. Look at the speed difference between a program written in C vs one written in PHP. The C program may have more upfront cost in code writing time and compiling, but if you are going to run it time and again, the C is going to be much faster. If you are going to run it once PHP is a better choice because there is less upfront cost. It really depends on the situation.
Efficiency is intelligent laziness.
I definitely agree with Mr. Solieri, but I think that you can compare this to a situation that I faced long (very long) time ago when I started to program. I started using Turbo Pascal 3.0, later 5.5 and a I remember you had the option to get the compiler do array boundary checking or not. It is not just a thing about when the error is catched, but what will happen when it is. In the strict languages (and life situations), the benefit is that you will always know WHY something went wrong, but in lazy evaluating languages, some situations may present only sometimes and not all the times you will know what may have gone wrong, therefore, strict: for the formal and prudent, lazy: for the brave and the bold.