Matthew and I would like to consult you about the API exposed to users of `base` for the `dataToTag#` operator.
dataToTag# :: forall (a :: Type). a -> Int#
getTag :: forall (a :: Type). a -> Int#
- 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
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
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'
Questions:
- Is this in scope for CLC? My answer is firmly yes: the API of the base library is one of the CLC's primary responsibilities.
- Should we open a ticket somewhere with the content of this email?
- Any thoughts about the design?
Thanks!
Simon