One of the positive side effects of this fact is that Haskellers have been forced to figure out proper error handling strategies, for the exact same reason Haskellers were forced to figure out proper effect management strategies (e.g. monadic IO). In fact, errors and effects are part of the same problem.
In imperative languages, the temptation to use evaluation sequencing as a hack for handling errors and effects has proven too tempting for every pre-Haskell language I'm aware of.
Agreed. Clojure uses lazy sequence by default. After ClojureScript is compiled to js, sometimes it's crazily hard to figure out why the error happened due to the obscure call site in the code.
Good point. Interestingly, there doesn’t seem to be a commonly known notion of evaluation that would blur the distinction between FEXPRs and functions — that is, one that would allow “functions” access to the unevaluated syntactic form of the arguments.
For example, the following Python code has the same evaluation semantics.
What's less clear is whether using lazy evaluation everywhere is a good idea. Certainly it has some really nice properties - for example it blurs the distinction between macros and functions by allowing arguments to be lazily evaluated.However, It can lead to hard to debug errors (as the error will not necessarily surface at the call site), and make it hard to reason about the performance and memory usage of code.