Skip to content

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.

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