unsafeCoerce#'s kind is not as liberal enough to inspect tag bits.
Inspecting dynamic pointer tagging bits cannot be done with unsafeCoerce# alone. You have to introduce an extra box:
import Foreign import Unsafe.Coerce import Data.Bits data Box a = Box a unsafeIsEvaluated :: a -> Bool unsafeIsEvaluated a = unsafeCoerce (Box a) .&. (sizeOf (undefined :: Int) - 1) /= 0
To see this operation in action, see the 'speculation' package.
There is of course the unsafeCoerce# primop, but it can't change kinds:
unsafeCoerce# :: a -> b
However, if unsafeCoerce# was able to switch to an unboxed kind:
unsafeCoerce# :: forall (b :: ??). a -> b -- 1
this could be done in one fell swoop without the extra box.
unsafeIsEvaluated a = unsafeCoerce# a `and#` (sIZEOF_INT# -# 1#)
Of course, this is far from the most liberal type, but
unsafeCoerce# :: forall (a :: ??). (b :: ??) -> b -- 2
would allow conversion to and from addres-sized unboxed types, although it would likely be risky from a GC perspective.
unsafeCoerce# :: forall (a :: ??). (b :: ?) -> b -- 3
might also be possible, but the interpretation with coercing into an unboxed tuple doesn't make much sense.
But overall the type given by (1) above is the most permissive possible without potentially disastrous interpretation consequences.