Swap
This example illustrates three of LARD's more interesting features:
classes, polymorphism and implicit parameters.
Classes
In lard the class of something is what "kind" of thing it is.
It doesn't have much in common with the use of the same term in
object-oriented languages. One aspect of the class of something is
often its type, but this is only part of it. Here are some of the
classes:
- type: the class of types.
- val(T:type): for each type T there is a class of
values of that type.
- var(T:type): for each type T there is a class of
variables of that type.
- class: the class of classes.
Var Parameters
The parameters to the gcd function in the last example were of class
val(int), indicating that they took values of type
int. It is often useful to have parameters of other classes.
Here is a function that swaps its two parameters:
swap(x:var(int),y:var(int)):expr(void)=(
tmp:var(int).
tmp:=x;
x:=y;
y:=tmp
).
A couple of points to note:
- The parameters x and y are of class
var(int), i.e. they are variables of type integer. It is
important that they are variables as otherwise it wouldn't be possible
to change them.
- The return type is void, indicating that no value is
returned.
It would be better if the function were capable of swaping variables
of any type. The following examples show how LARD allows this.
Type Parameters
LARD allows parameters to have the class type, and this can
help make the code more generic:
swap(T:type,x:var(T),y:var(T)):expr(void)=(
tmp:var(T).
tmp:=x;
x:=y;
y:=tmp
).
This version of the code takes an additional parameter T
which indicates the type of the variables to be swapped. T
is then used as the type in the declarations of x, y
and tmp. This version of swap would be called as follows:
swap(int,foo,foo2)
or
swap(bool,cond,xxx)
Implicit Parameters
Although this code allows variables of any type to be swapped it is a
little awkward to have to specify the type each time. To make things
easier LARD has a feature called implicit parameters. All the
parameters used so far are explicit parameters, that is they are all
listed explicitly in the declaration of the function and in the call.
An implicit parameter on the other hand appears in the declaration but
does not appear in the call. Here's how swap can be written using
implicit parameters:
swap(x:var(T:type),y:var(T)):expr(void)=(
tmp:var(T).
tmp:=x;
x:=y;
y:=tmp
).
The function still has three parameters, x, y, and
T, but T is now an implicit parameter within the
class of x. This can now be called without the need for an
explicit type parameter:
swap(foo,sprocket)
Note that x and y are still constrained to have the
same type. If you wanted to allow x and y to have
different types you would need two implicit parameters:
foo(x:var(Tx:type),y:var(Ty:type)):expr(void)=(...
This mechanism is used extensively to implement polymorphic functions
in the standard library. Examples include the assignment function
:=, the array indexing function _[_], and the
channel communication functions. These are all described in later
examples.