# Chapter 26. Linear Closure-Functions

A closure-function is a boxed record that contains a pointer to an envless function plus bindings that map certain names in the body of the envless function to values. In practice, a function argument of a higher-order function is often a closure-function (instead of an envless function). For instance, the following higher-order function list_map_cloref takes a closure-function as its second argument:

```fun{
a:t@ype}{b:t@ype
} list_map_cloref{n:int}
(xs: list (a, n), f: (a) -<cloref> b): list_vt (b, n)
```

Closure-functions can be either linear or non-linear, and linear ones can be explicitly freed in a safe manner. The keyword -<cloref> is used to form a type for non-linear closure-functions. As a variant of list_map_cloref, the following higher-order function list_map_cloptr takes a linear closure-function as its second argument:

```fun{
a:t@ype}{b:t@ype
} list_map_cloptr{n:int}
(xs: list (a, n), f: !(a) -<cloptr> b): list_vt (b, n)
```

As can be easily guessed, the keyword -<cloptr> is used to form a type for linear closure-functions. Note that the symbol ! indicates that the second argument is still available after a call to list_map_cloptr returns.

A typical example making use of list_map_cloptr is given as follows:

```fun foo{n:int}
(
x0: int, xs: list (int, n)
) : list_vt (int, n) = res where
{
//
val f = lam (x) =<cloptr> x0 + x
val res = list_map_cloptr (xs, f)
val () = cloptr_free (\$UNSAFE.cast{cloptr(void)}(f))
//
} (* end of [foo] *)
```

Note that a linear closure is first created in the body of the function foo, and it is explicitly freed after its use. The function cloptr_free is given the following interface:

```fun cloptr_free {a:t0p} (pclo: cloptr (a)): void
```

where cloptr is abstract. The cast \$UNSAFE.cast{cloptr(void)}(f) can certainly be replaced with something safer but it would make programming more curbersome.

There is also some interesting interaction between currying and linear closure-functions. In functional programming, currying means turning a function taking multiple arguments simutaneously into a corresponding one that takes these arguments sequentially. For instance, the function acker2 in the following code is a curried version of the function acker, which implements the famous Ackermann function (that is recursive but not primitive recursive):

```fun
acker(m:int, n:int): int =
(
case+ (m, n) of
| (0, _) => n + 1
| (m, 0) => acker (m-1, 1)
| (_, _) => acker (m-1, acker (m, n-1))
) (* end of [acker] *)

fun acker2 (m:int) (n:int): int = acker (m, n)
```

Suppose that we apply acker2 to two integers 3 and 4: acker2(3)(4); the application acker2(3) evaluates to a (non-linear) closure-function; the application of this closure-function to 4 evaluates to acker(3,4), which further evaluates to the integer 125. Note that the closure-function generated from evaluating acker2(3) becomes a heap-allocated value that is no longer accessible after the evaluation of acker2(3)(4) finishes, and the memory for such a value can only to be safely reclaimed through garbage collection (GC).

It is also possible to define a curried version of acker as follows:

```fun acker3 (m:int) = lam (n:int): int =<cloptr1> acker (m, n)
```

While the evaluation of acker3(3)(4) yields the same result as acker2(3)(4), the compiler of ATS (ATS/Postiats) inserts code that automatically frees the linear closure-function generated from evaluating acker3(3) after the evaluation of acker3(3)(4) finishes.

In ATS1, linear closure-functions play a pivotal role in supporting programming with higher-order functions in the absence of GC. Due to advanced support for templates in ATS2, the role played by linear closure-functions in ATS1 is greatly diminished. However, if closure-functions need to be stored in a data structure but GC is unavailable or undesirable, then using linear closure-functions can lead to a solution that avoids the risk of generatig memory leaks at run-time.

Please find on-line the entirety of the code used in this chapter.