4.4 Putting it in Prolog

Although it's more work than implementing an FSA recognizer, its not all that difficult to implement an RTN recognizer. Above all, we don't have to worry about stacks. Prolog (as you should all know by know) is a recursive language, and in fact Prolog has its own inbuilt stack (Prolog's backtracking mechanism is stack based). So if we simply write ordinary recursive Prolog code, we can get the behavior we want.

As before, the main predicate is recognize, though now it has four arguments

        recognize(Subnet,Node,In,Out)

Subnet is the name of the subnetwork being traversed, Node is the name of a state in that subnetwork, and In and Out are a difference list representation of the tape contents. More precisely, the difference between In and Out is the portion of the tape that the subnetwork Subnetwork recognized starting at state Node:

recognize(Subnet,Node,X,X) :-
    final(Node,Subnet).
recognize(Subnet,Node_1,X,Z) :-
    arc(Node_1,Node_2,Label,Subnet),
    traverse(Label,X,Y),
    recognize(Subnet,Node_2,Y,Z).

As in our work with FSAs, the real work is done by the traverse predicate. Most of what follows is familiar form our work on FSAs --- but take special note of the last clause. Here traverse/3 calls recognize/4. That is, unlike with FSAs, these two predicates are now mutually recursive. This is the crucial step that gives us recursive transition networks.

traverse(Label,[Label|Symbols],Symbols) :-
    \+(special(Label)).
traverse(Label,[Symbol|Symbols],Symbols) :-
    word(Label,Symbol).
traverse('#',String,String).
traverse(Subnet,String,Rest) :-
    initial(Node,Subnet),
    recognize(Subnet,Node,String,Rest).

One other small change is necessary: not only jumps and category symbols need to be treated as special, so do subnetwork names. So we have:

special('#').
special(Category) :- word(Category,_).
special(Subnet) :- initial(_,Subnet).

         
To be added: step through the processing of
Harry flies a broomstick.

Finally, we have some driver predicates. This one tests if a list of symbols is recognized by the subnetwork Subnet.

test(Symbols,Subnet) :-                          
    initial(Node,Subnet),                
    recognize(Subnet,Node,Symbols,[]). 

This one tests if a list of symbols is a sentence (that is, if it is recognized by the s subnetwork). Obviously this driver will only work if the RTN we are working with actually has an s subnetwork!

testsent(Symbols) :-                  
    initial(Node,s),                  
    recognize(s,Node,Symbols,[]).  

This one generates lists of symbols recognized by all subnetworks.

  
gen :- test(X,Subnet),  
       write(X),nl,  
       write('has been recognized as: '),write(Subnet),nl,nl,  
       fail.  

Last of all, this one generates sentences, that is lists of symbols recognized by the s subnetwork (assuming there is one).

gensent :-                         
   test(X,s),                       
   write(X),nl,                    
   write('is a sentence'), nl,nl,   
   fail.


Patrick Blackburn and Kristina Striegnitz
Version 1.2.4 (20020829)