Inferring uniqueness types

Folkert de Vries, august 2020

Pure FP: the ideal

Pure FP: Impementation

Referential transparency

An expression is

referentially transparent

when it can always be replaced by its definition without changing the program output

Referential transparency

copy original, modify copy

time space
Array set element O(1) O(1) ๐Ÿš€
Array copy & set element O(n) O(n) ๐ŸŒ

but copying is expensive:

we can modify values

ifย theyย are no longer used

we can modify values

ifย theyย are dead

1. Reclaim Memory

i.e. garbage collection

2. Destructive Updates

\texttt{Array.set index value array = ...}

if "dead", modify in-place

Runtime

compile time

  • accurate
  • runtime overhead
  • unpredictable
  • less precise
  • no overhead
  • statically guaranteed

System 1: Clean

System 2: UTS

Uniqueness Types

idea: annotate base types with a uniqueness attribute

\texttt{String}^\bullet
\texttt{String}^\times

values of a unique type can be updated destructively

unique string

non-unique string

Uniqueness Relations

\texttt{fst} :: (t^u, s^v)^{?} \xrightarrow \times t^u

UTS

idea: use logic expressions to encode relations

\bullet \text{: unique \& boolean True}
\times \text{: non-unique \& boolean False}

UTS

idea: use logic expressions to encode relations

\texttt{fst} :: (t^u, s^v)^{u \lor w} \xrightarrow \times t^u

My Problem

UTS inference is slow, and infers large types

My Problem

\texttt{swap} :: (s^v, t^u)^{u \lor v \lor w} \xrightarrow \times (t^u, s^v)^{w'}
\texttt{swap r = (snd r} \texttt{, fst r} \texttt{)}
\texttt{swap} :: (s^{(\lnot v \land u) \lor (\lnot v \land w) \lor (u1 \land u) \lor (u1 \land w)}, t^u)^{u \lor w} \xrightarrow \times (t^u, s^{(\lnot v \land u) \lor (\lnot v \land w) \lor (u1 \land u) \lor (u1 \land w)})^{v1}

Unification

idea: when are two types equivalent?

well-typed if the type of \(x\) matches the type of \(f\)'s argument

{f(x)}

Unification

idea: when are two types equivalent?

\alpha \doteq \texttt{Int}
S = [ \alpha \mapsto \texttt{Int}]
\texttt{Int} = \texttt{Int}

Unification

idea: when are two types equivalent?

syntactic unification is compositional

(barring the occurs check)

a \doteq c
b \doteq d
a \to b \doteq c \to d
S = [ a \mapsto c, b \mapsto d ]

Boolean Unification

idea: when are two formulae equivalent?

finds the (most-general) unifier

u1 \mapsto (\neg u2 \land v1) \lor (\neg u2 \land v2) \lor (u1 \land v1) \lor (u1 \land v2) \\ u2 \mapsto (u2 \land v1) \lor (u2 \land v2)
u1 \lor u2 \doteq v1 \lor v2

Boolean Unification

claim: not a good fit in practice

  • unneeded connectives are introduced
  • signatures become large
  • simplifying formulae is expensive

๐Ÿ˜•

Toward Solutions

faster unification of uniqueness attributes

๐Ÿš€

Disjunctions are for Containers

There is a hierarchy between variables

  • \(u, v\) are lower boundsย 
  • define \( w \) as an upper bound
  • \(w\) dominates \(u\) and \(v\)
( t^u, s^v)^{u \lor v \lor w }

There is a hierarchy between variables

Disjunction & Unique

we don't know which variable will be \(\bullet\), therefore have to keep all options available in the unifier

u \lor v \lor w \doteq \bullet

now we can immediately pick \(w = \bullet\)

w \geq u, v
\doteq \bullet

Disjunction & Unique

Disjunction & Disjunction

t^{(u_1 \geq u_2)} \doteq t^{(v_1 \geq v_2)}
  • unify dominators
  • accumulate dominated

Polymorphic records

\{ name :: String ~|~ a \} \doteq \{ age :: Int~|~ b \}
\{ age :: Int, name :: String ~|~ c \}

unifies to:

"at least field \(name\) and at least field \(age\)"

A Polymorphic Type System for Extensible Records and Variants (Gaster & Jones, 1996)

w \geq u, v \Rightarrow (w \geq \{ u, v | \alpha \})

Container Annotation

Record-Inspired Unification

(w_2, \{ u_1, \dots u_n, v_1, \dots v_m ~|~ \gamma \})

Container Unification

rules

Container Unification

deriving swap

Container Unification

deriving swap

Container Unification

deriving swap

Container Unification

deriving swap

r :: (t^u, s^v)^{( w2 \geq \{ u, v | \gamma \})}

inferred

inferred

r :: (t^u, s^v)^{( w \geq \{ u, v | \delta \})}

Technical Summary

Technical Summary

pure functional programs can be slow

Technical Summary

dead values can be modified destructively

Technical Summary

uniqueness type enable this

(and more)

Technical Summary

UTS is slow & infers large types

\texttt{swap} :: (s^{(\lnot v \land u) \lor (\lnot v \land w) \lor (u1 \land u) \lor (u1 \land w)}, t^u)^{u \lor w} \xrightarrow \times (t^u, s^{(\lnot v \land u) \lor (\lnot v \land w) \lor (u1 \land u) \lor (u1 \land w)})^{v1}

Technical Summary

Improved unification solves that

\texttt{swap} :: (s^v, t^u)^{(w \geq \{ u, v | \alpha \} )} \xrightarrow \times (t^u, s^v)^{w'}

Thanks to:

Sven-Bodo Scholz

Sjaak Smetsers

Edsko de Vries

Richard Feldman

Master Thesis

By folkert de vries

Master Thesis

  • 53