Skip to content

Officially sanction certain unsafeCoerce applications with unboxed unary tuples

It seems that it should be okay to unsafeCoerce between types that wrap certain things in unboxed unary tuples and ones that do not. For example,

unsafeCoerce :: (A -> B) -> A -> (# B #)
unsafeCoerce :: ((# A #) -> B) -> A -> B

Generally, I believe unsafeCoerce :: E1 -> E2 should be okay when the only differences are in what is wrapped in an unboxed unary tuple and both of the following hold:

  1. Each new unary tuple wrapper in E2 is in a positive position.
  2. Each new unary tuple wrapper in E1 is in a negative position.

Semantically,

unsafeCoerce :: (A -> B) -> A -> (# B #)
=
\f a -> let !fa = f a in (# fa #)

unsafeCoerce :: ((# A #) -> B) -> A -> B
=
\f !a -> f (# a #)

Am I correct in this interpretation? If so, is this something the developers would be willing to commit to and document? The first version in particular (a new unary tuple wrapper in positive position in the result) would be very useful for reducing both source code and generated code size in libraries supporting both strict and lazy operations.

Edited by David Feuer
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information