(Creating a new thread from State monad - memory exhausted - #27 by doyougnu)
Hi @doyougnu, I wonder if you could help me with something. I have been trying to understand cases where Unlifted
has benefits above and beyond Make invalid laziness unrepresentable (MILU). As I mentioned in an earlier comment, nothunks
was what originally prompted me to develop the idea of MILU, and achieve a type level guarantee that a value contains no thunks. For Lifted
types MILU doesn’t quite imply no thunks, because the value itself may be a thunk! It just implies that once the value is forced it no longer contains any thunks.
Of course, using Unlifted
types appropriately can be part of MILU. But I still don’t understand specific cases where using Unlifted
types provides more of a benefit than MILU with Lifted
types. Do you have any examples?
Something I’ve been wondering about is whether GHC can take advantage of strictness of return types of functions. For example, if I have a function
strictDup !x = (x, x)
can GHC take advantage of the fact that the fields of the tuple are already evaluated after the pair constructor is evaluated? For example, can it avoid an evaluation in
let (y, z) = strictDup x in y + z
From looking at the core, or even the STG, I don’t think so. It still converts to the following:
let (y, z) = strictDup x
in case y of Int# y' ->
case z of Int# z' ->
Int# y' z'
and I think the pattern match on Int#
requires an attempt at evaluation. In fact I don’t see any way to pattern match in Core or STG without attempting an evaluation too! As far as I can tell, the same holds even for
data StrictPair x y = StrictPair !x !y
strictPair' x = StrictPair x x
Now, if StrictPair
were defined to have two Unlifted
components then I think the evaluation could in principle be avoided, but again I don’t know if GHC’s intermediate representations are rich enough to express that.
Does anyone have any insight they can share?