Hello Haskell community. I’ve only been a spectator in this discourse so far, so this is my first time starting a post myself. Nice to meet you!
I thought I understood what strictness meant but I realized there were still some holes when I tried to put it into words more precisely.
I’m still a bit confused, so perhaps my formulation below may not be precise to begin with, but I’ll try my best.
I often see the definition:
f _|_ = _|_ <=> f strict
In purely theoretical terms, I think this definition makes sense.
But in Haskell discussions, strictness seems to mean more than just this.
For example, if we only care about the above definition, the following would be strict:
f !x = g x
f undefined -- undefined
f (1 + undefined) -- undefined
[Aside: actually, if I took the definition at face value, then id undefined = undefined so id would be strict as well. I’m not sure who is responsible (the function itself or the caller) for evaluating the arguments in this definition]
But I think in typical Haskell discussions, this isn’t what is meant by strictness, especially if g is lazy and accumulates a lot of thunks.
Instead we would need at least something like:
f' x = let !y = g x in y
and only then would we say f' is strict. (or even this isn’t enough depending on g, such as with foldl')
But we may also differentiate the two and say f is strict in its argument and f' is strict in its result, or something along those lines.
e.g.
Either way, it’s a bit different from the definition f _|_ = _|_.
Put another way, in Haskell discussions, strictness isn’t so much about the handling of bottom, but more about thunk accumulation and evaluation, which I believe are related but not exactly the same thing. e.g. foldl'
But there are also cases where strictness does refer to the original definition, like Data.Function
And I find myself easily confused when I start thinking about related topic like evaluation and WHNF, the evaluate function, packages with lazy and strict versions, memory leaks such as those in Control.Monad.Trans.Writer.Strict vs Control.Monad.Trans.Writer.CPS (not entirely due to strictness, but still part of the problem), etc
I was wondering if there is a more precise definition of these different strictnesses in Haskell, and whether there is some comprehensive resource on this topic (I’ve looked so far in common places like the language report, GHC docs, Haskell wiki).
Thank you!