A further combinator allows virtual code applications to interact
directly with any interactive console application using the
expect
library. The mechanism is similar to that of
interactive applications documented in the Output From Interactive Applications, but attempts to be more convenient.
Instead of being designed as an interactive application, any virtual
code application may use this combinator to spawn a shell and interact
with it in order to compute some desired result.
The advantage of this combinator over the library
combinator is
that it requires no modification of the virtual machine to support new
applications. It can also interact with applications that may reside
on remote servers, that are implemented languages other than C, or
whose source code is unavailable. For example, the GNU R statistical
package provides an interactive command to evaluate multivariate
normal distribution functions with an arbitrary covariance matrix, but
the corresponding function is not provided by the Rmath
C
library (or any other free library, to the author's knowledge) because
it is implemented in interpreted code. This combinator makes it
callable by an avram
virtual code application nevertheless. The
disadvantage compared to the library
combinator is that there
is more overhead in spawning a process than simply making a call to a
built in function, and the programming interface is more complicated.
The combinator takes the form
interact
]] f = ((nil,nil),(((nil,nil),nil),((nil,
f),nil)))
where f is the virtual code for a function that
follows the same protocol described in Output From Interactive Applications,
except that it does not allow file output as described in
Mixed Modes of Interaction. The argument x
is ignored when the
expression (interact f) x
is evaluated, similarly to the way the argument
is ignored in an expression like (constant k) x
. The result returned
is a transcript of the dialogue that took place between f
and the
externally spawned shell, represented as a list of lists of strings for
line oriented interaction, or a list of characters alternating with lists of
strings in the case of character oriented interaction.
The following example demonstrates a trivial use of the interact
combinator to spawn an ftp
client, do an ls
command, and then
terminate the session.
eof = <(nil,(nil,(((nil,nil),nil),(nil,nil))))> demo = interact conditional( conditional(identity,constant false,constant true), constant(0,<'ftp'>,<'ftp> '>), conditional( conditional(left,constant false,constant true), constant(1,<'ls',''>,<'','ftp> '>), conditional( compose(compare,couple(left,constant 1)), constant(2,<'bye',''>,<eof>), constant nil)))
Some liberties are taken with silly
syntax in this example, in
the way of using angle brackets to denote lists, and numbers to
represent states.
identity
function used as a predicate in the
conditional
, which is then negated). In that case it returns
the triple containing the initial state of 0, the ftp
shell
command to spawn the client, and the 'ftp> '
prompt expected
when the client has been spawned, both of the latter being lists of
strings.
left
function used as a predicate,
referring to the state variable expected on the left of any given
(state,input)
pair, also negated). If so, it returns the triple
containing the next state of 1, the ls
command followed by an
empty string to indicate a line break, and the expected prompt
preceded by an empty string to match it only at the beginning of a
line.
bye
command to close the session, eof
rather than a
prompt to wait for termination of the client, and a state of 2.
nil
value to indicate that the computation has
terminated.
Deadlock would be possible at any point if either party did not follow
this protocol, but for this example it is not an issue. If an
expression of the form demo x
were to be evaluated, then
regardless of the value of x
, the value of the result would be
as shown below.
< <'ftp'>, <'ftp> '>, <'ls',''>, <'ls','Not connected.','ftp> '>, <'bye',''>, <'bye',''>>
That is, it would be a list of lists of strings, alternating between the
output of the interactor and the output of the ftp
client. If
the spawned application had been something non-trivial such as a
computer algebra system or a command line web search utility,
then it is easy to see how functions using this combinator can leverage
off a wealth of available resources.