Strictness of dataToTag argument

Viewed 410

In GHC.Prim, we find a magical function named dataToTag#:

dataToTag# :: a -> Int#

It turns a value of any type into an integer based on the data constructor it uses. This is used to speed up derived implementations of Eq, Ord, and Enum. In the GHC source, the docs for dataToTag# explain that the argument should already by evaluated:

The dataToTag# primop should always be applied to an evaluated argument. The way to ensure this is to invoke it via the 'getTag' wrapper in GHC.Base:

getTag :: a -> Int#
getTag !x = dataToTag# x

It makes total sense to me that we need to force x's evaluation before dataToTag# is called. What I do not get is why the bang pattern is sufficient. The definition of getTag is just syntactic sugar for:

getTag :: a -> Int#
getTag x = x `seq` dataToTag# x

But let's turn to the docs for seq:

A note on evaluation order: the expression seq a b does not guarantee that a will be evaluated before b. The only guarantee given by seq is that the both a and b will be evaluated before seq returns a value. In particular, this means that b may be evaluated before a. If you need to guarantee a specific order of evaluation, you must use the function pseq from the "parallel" package.

In the Control.Parallel module from the parallel package, the docs elaborate further:

... seq is strict in both its arguments, so the compiler may, for example, rearrange a `seq` b into b `seq` a `seq` b ...

How is it that getTag is guaranteed to behave work, given that seq is insufficient for controlling evaluation order?

1 Answers
Related