Just a nitpick, but Haskell's scheduler (like Go's) is "less preemptive" than Erlang's. If you have e.g.
i = 0
for{
i += 1
}
or equivalent in Go/Haskell, then the HS thread/goroutine running it cannot be interrupted, as interruption can only take place at certain points (e.g. allocation or function calls).
Erlang on the other hand assigns a certain amount of time units to each process, and each pure-Erlang operation consumes these, so an Erlang process can always be interrupted as it will eventually use up this time allocation and yield (unless it's actually calling a C function etc).
Haskell's scheduler preempts on memory allocation. Memory allocation is ubiquitous in Haskell; the example you are giving cannot really be written in Haskell as values are immutable. You could try to do something with IORef and bang patterns to avoid thunks being allocated but you are now in a very tiny corner case, much smaller than the surface area of NIFs that can cause you problems in both Erlang and Haskell.
Admittedly, Haskell is less preemptive than Erlang, but definitely not at the same level as Go.
A mutating variable is not what you commonly use in Haskell, so the idiomatic equivalent of your code would have memory accesses anyway, and it would be possible to interrupt it.
When your CPU intensive code does not allocate, it will not switch to another green thread.
So point in the example above is absence of memory allocation. And, having decent codegenerator, Haskell could produce the code above where registers are reused for new values (effectively, mutation).
Yes, an Erlang process can be interrupted at any point, unlike Go/Haskell, but this is at the cost of bytecode interpretation. I'm not saying it is bad, but there is a tradeoff.
Erlang on the other hand assigns a certain amount of time units to each process, and each pure-Erlang operation consumes these, so an Erlang process can always be interrupted as it will eventually use up this time allocation and yield (unless it's actually calling a C function etc).