Version 5 (modified by benl, 4 years ago) |
---|

# Closure Typing

## Region sharing

Consider the following function:

f () = do x = 5 g () = x g

Without closure information this function would have the following extended type:

f :: forall %r. () -> () -> Int %r

Remember that the `forall %r` at the front of the type is supposed to indicate that the return value is freshly allocated. This is certainly true if we apply both arguments:

twoSeparateInts :: Tuple2 %r1 (Int %r2, Int %r3) twoSeparateInts = (f () (), f () ())

In the type of `twoSeparateInts`, the different regions variables on each of the `Int` constructors means that they do not alias. This in turn means that it is safe to treat one as `Const` and the other as `Mutable`.

But what happens if we partially apply `f`? The standard type system will re-generalize the type for the new binding and we're left with:

f_unit :: forall %r1. () -> Int %r1 f_unit = f ()

We've now got a function which returns the *same* `Int` every time we call it, but the type says it's supposed to be fresh! The problem here is that `x` was free in our original definition of `g` so is shared between applications of it.

## Closure typing for region sharing

Closure typing is used to track the sharing of regions between function calls.

The type inferred for `f` is actually:

f :: forall %r0 . () -> () -($c0)> Int %r0 :- $c0 = x : %r0

The `$c0` annotation tells us that this function has a object free in its closure, and that the object contains region `%r0`. The `x : %r0` syntax gives a name to this term, and is pronounced "x *of* region zero".

If we use this new type and apply the first argument we have:

f_unit :: () -($c0)> Int %r0 :- $c0 = x : %r0

This type says that `f_unit` is a function that takes a unit value and returns an `Int`, but the `Int` is free in its closure so is shared by all calls to it. The type system does not generalise regions which are free in these closures.