.he'PFUNCTIONS''Page %'
.fo'Steve Hardy'- % -'October, 1977'
.ce2
Pattern Directed Invocation of Functions
.br
=========================================
.sp
This handout describes a package which simplifies the programming of
systems like ELIZA, CONVERSE, etc. Before reading this you ought to
read the MATCH demo
and probably the ELIZA demo as well.
.sp
PFUNCTIONS (or 'pattern functions`) have a 'pattern` associated with them and
take a list as argument. If the list does not 'match` their pattern
PFUNCTIONS do nothing, otherwise they run just like normal functions. For
example:
 	: PFUNCTION MCUE([== MOTHER ==]);
 	:	[TELL ME MORE ABOUT YOUR FAMILY] =>
 	: END;
.br
This defines a pattern function, called MCUE, whose associated pattern is [==\ MOTHER\ ==].
This pattern matches any list containing the word MOTHER so executing
 	: MCUE([MY MOTHER IS CALLED MEG]);
.br
causes the following to be printed out;
 	** [TELL ME MORE ABOUT YOUR FAMILY]
.br
Applying MCUE to a list not containing MOTHER causes absolutely nothing to
happen.
.sp
Here is a more complicated example:
 	: FUNCTION IAM([I AM ??STATE]);
 	:	[WHY ARE YOU ^^STATE] =>
 	: END;
.br
IAM works on lists beginning with the words I AM, for example:
 	: IAM([I AM WRITING A HANDOUT]);
 	** [WHY ARE YOU WRITING A HANDOUT]
.br
Like "==", the pattern element ??STATE matches any sequence of words
but also sets the value of the variable STATE to a list of the matched words
(in this case [WRITING A HANDOUT]) for later use.
.sp
There is a function, called RUNALL, to simplify the use of PFUNCTIONS.
It takes as argument a 'stimulus` (ie a list, usually of words) and a list of pattern
function names, for example:
 	: RUNALL([I AM LIKE HER MOTHER], [MCUE IAM]);
 	** [TELL ME MORE ABOUT YOUR FAMILY]
 	** [WHY ARE YOU LIKE HER MOTHER]
.br
If none of the pattern functions match the stimulus then nothing happens
when RUNALL is called.
.sp
Usually, it is more convenient to have functions return results rather
than print things directly. Consider the following functions to simplify
arithmetic expressions:
 	: PFUNCTION S1([?X PLUS NOTHING]);
 	:	X
 	: END;
.br
This says that the result of adding anything, lets call it X, to NOTHING is
X, for example:
 	: S1([TEN PLUS NOTHING]) =>
 	** TEN
 	: S1([[TEN TIMES TWENTY] PLUS NOTHING]) =>
 	** [TEN TIMES TWENTY]
.br
Notice that S1 doesn't work in the following case:
 	: S1([NOTHING PLUS TEN]) =>
 	**
.br
so we have:
 	: PFUNCTION S2([NOTHING PLUS ?X]);
 	:	X
 	: END;
.br
To simplify using these (and perhaps other) routines we could have a function
called SIMPLIFY, thus:
 	: FUNCTION SIMPLIFY(E);
 	:	RUNALL(E, [S1 S2 ...])
 	: END;
.br
We can use this new function thus:
 	: SIMPLIFY([MYAGE PLUS NOTHING]) =>
 	: MYAGE
.br
That is, if you add my age to nothing you get my age.
.sp
Unfortunately, RUNALL is a bit unpredictable when used to return
results - any number of patterns might match and you might get any number
of results, for example
 	: SIMPLIFY([MYAGE PLUS THREE]) =>
 	**
 	: SIMPLIFY([NOTHING PLUS NOTHING]) =>
 	** NOTHING NOTHING
.sp
Fortunately, there are two alternatives to RUNALL. The most useful is
GETONE. This takes the same arguments as RUNALL and tries the pattern
functions in turn until one returns a result (if none return results
GETONE returns FALSE).
GETONE waits for a result - not just a match, so the following is
sensible:
 	: PFUNCTION PRDN1([I AM SORRY]);
 	:	IF MISTRUST > 0.8 THEN
 	:		[YOU DONT FOOL ME WITH FAKE APOLOGIES]
 	:	CLOSE
 	: END;
 	: PFUNCTION PRDN2([I AM SORRY]);
 	:	IF MISTRUST < 0.2 THEN
 	:		MISTRUST * 0.5 -> MISTRUST;
 	:		[I AM SORRY TOO]
 	:	CLOSE
 	: END;
 	: PFUNCTION PRDN3([I AM SORRY]);
 	:	IF MISTRUST >= 0.2 AND MISTRUST <= 0.8 THEN
 	:		[THATS OKAY]
 	:	CLOSE
 	: END;
.sp
The second alternative
to RUNALL
is GETALL - this returns a
list of all the results, for example:
 	: GETALL([MYAGE PLUS TEN], [S1 S2]) =>
 	** []
.br
That is the expression [MYAGE\ PLUS\ TEN] cannot be simplified by either
S1 or S2.
A second example, relevant to the ELIZA demo might be:
 	: FUNCTION REPLYTO(INPUT);
 	:	ONEOF(GETALL(INPUT, [MOTHER PRDN1 PRDN2 PRDN3 ...]))
 	: END;
.br
Here, all possible replies are found and then ONEOF used to pick at random.
.sp
The PARRY and BLOCKS2 demos illustrates further use of PFUNCTIONS.
