As virtual machine interfaces to external libraries accumulate faster
than they can be documented and may vary from one installation to
another, it is helpful to have a way of interrogating the virtual
machine for an up to date list of the installed libraries and
functions. A combinator called have
can be used to test for the
availability of a library function. It takes the form
have
]] (x,y) = ((nil,nil),((nil,
x),(nil,
y)))
where x is the name of a library and y is the name of a
function within the library encoded as character strings. For example,
if x is 'mtwist'
and y is 'u_disc'
(for the
natural random number generator function in the Mersenne twistor
library) then have(
x,
y)
is a function that returns
a non-empty value if an only if that library is installed and that
function is available within it. The actual argument to the function
is ignored as the result depends only on the installed virtual machine
configuration. In this sense, it acts like a constant
combinator.
One way for this combinator to be used is in code of the form
portable_rng = conditional( have('mtwist','u_disc'), library('mtwist','u_disc'), some_replacement_function)
which will use the library function if available but otherwise use a replacement function. Code in this form makes the decision at run time, but it is also possible to express the function such that the check for library presence is made at compile time, as the following example shows, which will imply a slight improvement in performance.
non_portable_rng = apply( conditional( have('mtwist','u_disc'), constant library('mtwist','u_disc'), constant some_replacement_function), 0)
This program would be non-portable in the sense that it would need to
be recompiled for each installation if there were a chance that some
of them might have the mtwist
library and some might not,
whereas the previous example would be binary compatible across all of
them. 1
The actual value returned by a function have(foo,bar)
is the
list of pairs of strings <(foo,bar)>
if the function is
available, or the empty list otherwise. A non-empty list is
represented as a pair (head,tail)
, and an empty list as
nil
. The angle bracket notation <a,b,c...>
used here is
an abbreviation for (a,(b,(c...nil)))
.
Either or both arguments to the have
combinator can be a
wildcard, which is the string containing a single asterisk,
'*'
. In that case, the list of all available matching library
names and function names will be returned. This feature can be used to
find out what library functions are available without already knowing
their names.
If a library had a function named '*'
, which clashes with
the wild card string, the interpretation as a wild card would take
precedence.
[1] In practice both examples are equally portable because
the mtwist
source is distributed with avram
so all
installations will have it. Most libraries are distributed
separately.