-
Notifications
You must be signed in to change notification settings - Fork 18
Description
Matthew and I would like to consult you about the API exposed to users of base
for the dataToTag#
operator.
Currently we have a primop
dataToTag# :: forall (a :: Type). a -> Int#
and a strangely named alias in GHC.Base
getTag :: forall (a :: Type). a -> Int#
getTag x = dataToTag# x
Of course this is all wrong:
dataToTag#
is way too polymorphic: it can't possibly work for every type- It is levity-monomorphic, so you can't use it on unlifted data types
- Plus, its implementation is a mess -- there is an ad hoc check that all uses of
dataToTag#
are to data types; but it's a fragile check,.
So Matthew is fixing that by introducing
type DataToTag :: forall {lev :: Levity}. TYPE (BoxedRep lev) -> Constraint
class DataToTag a where
dataToTag# :: a -> Int#
That fixes both things at one blow:
dataToTag#
now has a type class constrained type, so it's not over-polymoprhic- Both the class and its operation are levity-polymorphic.
- The implementation is very nice; no hacks any more.
So far so good: it's a change, but a backward-compatible change.
But we'd also like to kill off the strangely named getTag
while we are about it (with a deprecation cycle). And we propose to define
dataToTag :: forall (a :: TYPE LiftedRep). DataToTag a => a -> Int
dataToTag' :: forall (a :: TYPE UnliftedRep). DataToTag a => a -> Int
as wrappers for dataToTag#
that return a civilised boxed Int. It would be nice to make these levity-polymorphic too, but you can't write
dataToTag x = I# (dataToTag# x)
because there is a levity-polymorphic binder x
.
An alternative would be to put dataToTag into the class like this
class DataToTag a where
dataToTag# :: a -> Int#
dataToTag :: a -> Int
and now dataToTag can be levity-monomorphic. But the implementation is significantly more fiddly, because we have to build that dictionary on the fly.
The naming of the unlifted version is up for grabs. I suggested dataToTag'
by analogy with foldl'