Forcing a value, even if it has already been evaluated, has a small but present value.
If you have a pointer to something that may or may not have already been evaluated (thunk or value), and you wrap it in a lazy data constructor, you simply copy this address to its place in memory. It is fast.
If you have such a pointer, and you want to store it in a strict constructor, you must first evaluate it. This requires checking the low bits of the pointer for possible tags (a trick indicating an estimate). If there is no tag, you will actually go to this pointer to enter thunk. Before you do this, you must push the return frame onto the stack so that the execution flow returns to you at the end. Then thunk evaluates itself, puts the result in a register, and goes to the return address. Then you can put this result in memory.
So, even if the item you are pointing to has already been rated, you still need to check the tag. And I believe that in some cases the things being evaluated do not have a tag (this is optional), so all other work can still happen - for nothing.
Joachim breitner
source share