<p dir="ltr">I'm wondering if there would be a benefit, if not to the average programmer, then to the ones working on deeper/faster code, to allow some of the # kinded types (mostly Int#, Word#, Char#, Float#, Double#) to be used in Safe code, and to have typeclasses able to work with them.</p>
<p dir="ltr">For instance, the definition of Show would become:</p>
<p dir="ltr">class Show (a :: TYPE r) where<br>
  show :: a -> String<br>
  default show :: (r ~ 'LiftedRep) => a -> String<br>
  show x = showsPrec 0 x ""</p>
<p dir="ltr">  showsPrec :: Int -> a -> ShowS<br>
  default showsPrec :: (r ~ 'LiftedRep) => Int -> a -> ShowS<br>
  showsPrec _ x s = show x ++ s</p>
<p dir="ltr">  showList :: (r ~ 'LiftedRep) => [a] -> ShowS<br>
  showList ls s = showList__ shows ls s</p>
<p dir="ltr">The fact that the defaults only work when the type is a LiftedRep is a nonissue, because there's only a finite number of non-lifted types we'd be defining it for.</p>
<p dir="ltr">You could do the same with Eq, Ord, Num, Real, Integral, Fractional, Floating, RealFrac, RealFloat, Semigroup, Monoid, Bits, FiniteBits, and probably several others I can't think of right now. However, with the functions that return pairs, you'd need a version that returns an unboxed pair instead. Assuming you changed ReadPrec, you could even do the same with Read:</p>
<p dir="ltr">newtype ReadP (a :: RuntimeRep r) = ReadP (forall b. (a -> R b) -> R b)<br>
newtype ReadPrec (a :: RuntimeRep r) = ReadPrec (Int -> ReadP a)</p>
<p dir="ltr">IO, ST, and STM could be made polykinded the same way, and would open up Storable. However, how to do a definition for Monad that works for polykinded monads is an issue. I do know that RebindableSyntax handles it easily when there's just one monad that can operate on multiple kinds, though.</p>
<p dir="ltr">As for which # types could be exposed, I'm thinking that Char#, Int#, Word#, Float#, Double#, and Proxy# wouldn't be able to break out of Safe code. Int64# and Word64# would work as well, and for 64-bit machines would just be type aliases for Int# and Word# respectively. For types which have functions with undefined behavior for some arguments, you can just make wrappers that check the arguments and error out for the bad values. MutVar#, MVar#, TVar#, and StableName# don't open up any functions that would be unsuitable for safe code, either. I'm pretty sure that Array# and MutableArray# would also be safe, as long as all functions were length-checked and threw errors instead of having undefined behavior.</p>
<p dir="ltr">As for why this would be a desirable thing? Mostly for the sake of convenience and generality, I think. I find myself working with unboxed values from time to time, and it's a pain to always remember to use (+#) for Int# and plusWord# for Word#. In addition, having typeclasses that can return unboxed values (like a hypothetical sized# :: Sized a => a -> Int# vs sized :: Sized a => a -> Int) can improve the generated code when the code using the typeclass doesn't get specialized.</p>
<p dir="ltr">The module to import these would have to explain the differences between # kinded types and * kinded ones: # values aren't lazy; they can't be top-level definitions; you can't use unboxed tuples or sums with GHCi; and with a few exceptions, you can't place them in containers (you can't have an [Int#], for instance).</p>