For simple, unstructured datatypes such as Int
or Double
, turning them into strict fields is often a good default. That makes their space consumption very predictable (and constant). While it's possible that performance degrades due to performing unnecessary computations, this is, in general unlikely. For example, keeping track of a position is usually extremely simple and inexpensive, so there's nothing to be afraid of in terms of performance, and having predictable space behaviour is far more important.
An additional advantages of making simple types strict is that they can often be unpacked, i.e., stored directly within the constructor instead of via an additional indirection (there are pragmas or compiler flags for it). For small types, this usually is an advantage.
For structured datatypes such as lists or trees, the situation is far more complicated. A simple !
will rarely help here, because it only forces to WHNF. An evaluated list or tree can also easily be more costly in terms of space than an unevaluated thunk. Nevertheless, it sometimes makes sense to make such data strict as well. In such cases, you usually would wrap the constructor using a function (a so-called smart constructor) that establishes strictness invariants by calling deepseq
in appropriate places.