Local variables

AUSTRA is a functional language, so it has a functional technique for declaring what in a procedural language would be temporal or local variables.

LET clauses

The functional technique for declaring local variables in a formula is the let clause.

Austra
let m = matrix::lrandom(5),
    m1 = m * m',
    c = m1.chol in
    (c * c' - m1).aMax

In the above example, a lower triangular random matrix is computed, and it is multiplied by its transpose. Then, the Cholesky transform is calculated and finally we check that the transform is valid, evaluating the absolute maximum of the matrix difference.

The m, m1 and c variables only exist while the formula is being evaluated. As the example shows, each variable defined in the let clause can use any of the previously declared variables in the same clause.

Script-scoped LET clauses

When writing several statements in a script, let/in clauses are valid only for the statement they precede, but not for other statements:

Austra
let m = matrix::lrandom(5),
    m1 = m * m',
    c = m1.chol in
    (c * c' - m1).aMax;
-- The next statement cannot use "m".
m

If you need a local variable to be available for all statements that follow in a script, you must use a variant of let which does not terminate with an in keyword, but with a semicolon:

Austra
let m = matrix::lrandom(5);
-- Now, "m" is available for the rest of the script.
let m1 = m * m', c = m1.chol in (c * c' - m1).aMax; -- The next statement is valid. m

  Note

Some functional languages, as Haskell, feature another construct for abstracting sub-expressions. Haskell, for instance, offers both let and where. let is located before the expressions that make use of it, and where comes after the main expression.

In AUSTRA, we prefer let, for the sake of Code Completion. So far, I cannot think of any use for where that cannot be solved better with let.

Local function definitions

Functions can be defined in let clauses. For instance:

Austra
let mcd(a, b: int): int = if a % b = 0 then b else mcd(b, a % b) in
    mcd(80, 140)

In the above example, the function is defined in a let/in clause, but it could also be defined as a script-scoped local function.

  Note

Since mcd is recursive, its return type must be declared in the function header.

Function definitions may have their own local variables, as in this variant of the above example:

Austra
let mcd(a, b: int): int =
    let m = a % b in iff(m = 0, b, mcd(b, m)) in
        mcd(80, 140)

This way, we save one evaluation of the remainder.

Local functions may also be declared inside other functions. For instance, this code defines a function for the factorial, but uses an intermediate function that can be evaluated using tail recursion, for efficiency:

Austra
let fact(n: int) =
    let f(n, acc: int): int = iff(n <= 1, acc, f(n - 1, n * acc)) in
        f(n, 1);
fact(10);

Please note that the in keyword applies to the right-side of the definition of factorial. The let clause that defines factorial, on the contrary, is a script-level clause, with no associated in.

See Also