Unboxed tuples with multiplicity parametric fields
Motivation
Currently, an unboxed tuple always have all fields linear. This is fine for most purpose but it actually does hamper optimisations. This is a problem which only happens on code using -XLinearTypes
, therefore it's not too serious, but still we ought to make good by it.
Specifically, it concerns the CPR transformation when the returned argument has an unrestricted field (e.g. the Unrestricted
datatype which has a single unrestricted field). The story is expounded in the wiki page. Let me copy the explanation here.
Consider a function
f :: Int -> Unrestricted A
The argument type doesn't matter, the result type does.
The CPR split yields:
$wf :: Int -> (# A #)
f x = case_1 $wf x of
(# y #) -> Unrestricted y
This is ill-typed unless (# #)
has an unrestricted field (currently, all fields of an unboxed tuple are linear).
Therefore, CPR is restricted to the case where the constructor only has linear field.
Proposal
To be able to activate the CPR worker/wrapper split on data types with an unrestricted field, unboxed tuple should be parametrised by the multiplicity of their field, that is
type (#,#) :: forall r s. Multiplicity -> Multiplicity -> TYPE r -> TYPE s -> TYPE …
data (#,#) p q a b where
(#,#) :: a #p-> b #q-> (#,#) p q a b
At least the unboxed tuples used by Core should have such a type. It can also be a user-facing feature.
Alternative
An alternative is to have a single additional unboxed data type
data Unrestricted# a where
Unrestricted# :: a -> Unrestricted# a -- unrestricted field
And we could use (# a, Unrestricted# b #)
in CPR as the unboxed stand in for a data type which is linear in its first field and unrestricted in its second field.