The %free directive and parametrised scripts
It is permitted to construct a script containing definitions which are
dependent on information which will be supplied only when the script is
made the subject of a %include directive. Such a script is said to be
parametrised. This is indicated by the presence in the script of a
directive of the form
%free { signature }
where `signature' is a list of specifications of the identifiers for
which bindings will be provided at %include time. A script may contain
at most one %free directive, which must therefore give all the
identifiers on which the script is parametrised. The %free directive
may appear anywhere in the script, but for clarity it is recommended
that you place it at or near the top.
For example a script (called "matrices" say) defining the notion of
matrix sum and matrix product, for matrices of as-yet-unspecified
element type, could be written as follows:-
%export matmult matadd
%free { elem :: type
zero :: elem
mult, add :: elem->elem->elem
}
matrix == [[elem]]
matadd :: matrix->matrix->matrix
matadd xx yy = [[add a b|(a,b)<-zip2 x y]|(x,y)<-zip2 xx yy]
matmult :: matrix->matrix->matrix
matmult xx yy = outerprod innerprod xx (transpose yy)
innerprod x y = sum [mult a b|(a,b)<-zip2 x y]
where
sum = foldr add zero
outerprod f xx yy = [[f x y|y<-yy]|x<-xx]
Note that the identifiers declared under %free may denote types as well
as values. When we write a %include directive for the above script we
must provide bindings for all of its free identifiers. The bindings are
given in braces following the pathname (and before the aliases, if any).
Thus:-
%include "matrices" {elem==num; zero=0; mult=*; add=+; }
In the scope of the script containing the above directive the
identifiers `matmult' and `addmult' will be available at type
[[num]]->[[num]]->[[num]] and will behave as if their definitions had
been written using 0, (+), (*) in place of the identifiers zero, add,
mult.
The order in which the bindings are given is immaterial (it need not be
the order in which the identifiers occurred in the %free directive) but
a binding must be given for each free identifier of the %included
script. Note that the binding for a type is given using `==' and for a
value using `='. If the types of all the bindings (taken together) are
not consistent with the information given in the free directive of the
%included script, or if any required binding is missing, the compiler
will reject the %include directive as incorrect.
The main advantage of a parametrised script is that different bindings
may be given for its free identifiers on different occasions. For
example the same script "matrices" may be invoked with different
bindings to provide a definition of matrix addition and multiplication
over matrices with elements of type bool. Thus:-
%include "matrices" {elem==bool; zero=False; mult=&; add=\/; }
It is even possible to %include the same parametrised script twice in
the same scope (presumably with different bindings for the free
identifiers) but in this case it will be be necessary to alias apart the
two sets of exported identifiers to avoid a nameclash. So we might add
`b_matadd/matadd b_matmult/matmult' to the above directive if it were
being used in the same script as the previous one.
Miscellaneous points
By default the identifiers declared %free in a parametrised script are
not exported from the script. As always this can be overridden by
explicitly listing them in an %export directive.
Free typenames of non-zero arity are declared in the following style.
%free { stack * :: type
table * ** :: type
...
}
The corresponding bindings could be as follows
%include ... {stack * == [*]; table * ** == [(*,**)]; ... }
When a parametrised script exports a locally created typename (other
than a synonym type), each instantiation of the script by a %include is
deemed to create a NEW type (this is relevant to deciding whether or not
two types are the same for the purpose of readopting a type orphan, see
previous manual section). This is because the compiler assumes that an
abstract or algebraic type defined in a parametrised script will in
general have an internal structure that depends on the free identifiers.
Finally note that the bindings for the free identifiers of a
parametrised script must always be given EXPLICITLY. For example
suppose we wish to %include the file "matrices" in a script already
containing a type called `elem' over which we intend to do matrix
multiplication. We must write
%include "matrices" {elem==elem; etc. }
The binding `elem==elem' is not redundant, nor is it cyclic, because the
two `elem's involved refer to two different scopes (on the left of the
binding, that of the includee, and on the right that of the script
containing the directive).