Introduction. For some time I have been aware that areas of Artificial Intelligence develop rapidly to become the centre of attention, more so than in many other academic disciplines. But in any subject which is undergoing change, one must be sure neither to be carried along unprotestingly, nor to reject out-of-hand any unexpected changes of, say, methodology or the sphere of study. Such major revisions in the domain and purpose of a subject happen from time to time, and when they do, it is for all interested parties to explore and constructively criticise the developments. In Linguistics in the mid 1950's there was a major change with the introduction of transformational generative grammar, which, modified several times, has dominated theoretical syntax for over 20 years, though the future of transformational grammar (not generative grammar, of which it is a type) is currently under some question. As in theory "a generative grammar is a mathematically precise specification of the grammatical structure of the sentences that it generates" (p126,Lyons), it should be easy enough to computerise: indeed, if serious problems were to occur in implementation, this would point to a need for modifications. This computerisation of transformational grammar has been carried out, by Joyce Friedman for example, and did at the time serve as a test of the theory. Her programme later served as a machine by which different transformational rules could be tested automatically, which quickly shows up any mistakes in the rules used. In my project I have attemped to devise a programme which will also test different rules, within the version of transformational grammar that has been encoded. Problems encountered in coding can be looked at as a fairly important part of the exercise too, for they show up parts of the theory which are not adequately described, and if used in practice, would result in individual decisions on the course of action to be taken. I do not pretend to have proved the existence of trouble spots about which I intend to write post haste to Noam Chomsky, the founder of T.G. (transformational grammar) but the idea is valid that if anyone who followed the specifications came up with a non-functioning system, then that would be the fault of the specifications, and they should be changed. The thing that I have concentrated on in writing this programme though is the production of a model of T.G. that will take transformations, specified by the user,and a Deep Structure produced by PROLOG with its built-in mechanisms, and apply the transformations to the Deep Structure in an order also specified by the user, in order to see exactly what happens. The programme prints the D.S. and the result so far, with the name of the transformation as it goes along so that the user can see where things go amiss, or not, as the case may be. More importantly, I believe, is the way the programme carries out the tree changes, for I have tried to make these as close a model as I can to the way a Linguist would do it. I will therefore firstly describe the usual T.G. formalism and method, before going on to demonstating in what ways I have managed to construct an accurate model in PROLAPSE (PROlog Linguistics & Artificial intelligence Programme for Syntactic Engineering) and describing a few bits of code in detail that are of interest. Background. Assigning Structures to the constituents of a sentence using trees or bracket notation is not problematic and results in a clear analysis, unless the constituents are discontinuous, as in phrasal verbs... 1) He called her up every night. 2) *He called up her every night. 3) He called up his girlfriend every night. 4) He called his girlfriend up every night. The verb can be represented out of context as { CALL UP } and its structure as... verb(verb(call),particle(up)) The problem lies in 1,4 because the object of the verb comes between the verb and the particle ( UP is not a preposition here), and in that 2 is ungrammatical if unstressed. How then can the linguist show that { CALL UP } is a verb, which in 3, the only unproblematic sentence, is bracketed as shown? Clearly, if the two words are treated as unrelated, the grammar fails to reflect the underlying structure in which they are, really, a single unit, and in 1,4 they cannot be treated as a constituent since the object is between, and branches of a tree can't cross. Chomsky, looking at problems like the assignment of structures to related sentences, devised his theory, whereby a structure called the Deep Structure (D.S.) is transformed into another form, which is either transformed again, or is the Surface Structure (S.S.), i.e. a sentence of the language. The grammar, therefore, controls the derivation process rather than directly specifying the derived structure. There are in fact two types of rule: the P-S (Phrase Str.) rules of the D.C.G. (Definite Clause Grammar), which derive the D.S. rather than the S.S. which they do in non-transformational grammars; and the T-rules (Transformational), the nature of which I will now describe, basing my notation on that used by Brown and Miller (1982), with which I am most familiar, the book being the set text for Linguistics 2. Linguistic Notation and Method. Notation. For an example transformation I will use that for the Passive. 5) Passive. Sa: NP X Pass Verb NP 1 2 3 4 5 Sc: 5 2 3 4 PP[Prep[by],1] This transformation maps Fig.1a onto Fig.1b and, equivalently, Fig.2a onto Fig.2b. After this only the PROLOG bracket notation will be used. Fig.1a. S NP VP the man Aux Verb NP X Pass hit it be en Fig.1b. S NP VP it Aux Verb PP X Pass hit Prep NP be en by the man Fig.2a. s(np(det(the),noun(man)),vp(aux(X,pass(be,en)),verb(hit),np(pro(it)))) Fig.2b. s(np(pro(it)),vp(aux(X,pass(be,en)),verb(hit),pp(prep(by), np(det(the), noun(man))))) Method. 1).If the Sa. matches the tree, continue. Else fail. 2).Give each node on the tree mentioned by the Sa. its code number. 3).Taking each element of Before in turn, alter it and the tree in the way specified by After. 4).Remove the code numbers. Note that it is the tree that is altered, not the Sc. The Sc. is the rule specifying how the tree is to be changed. In the transformation in 5 there are different types of changes, and I will now list the different sorts that are possible, as exemplified by the passive rule and the mock rule in 6. 6). T-rule. Sa: {s,t} u v w X y z 1 2 3 4 5 6 7 Sc: 1+[sg] 2 3>7 0 5-6 4 np[...] Types of Change. Identity. When a number in the first row of the Sc. (Before) has under it in the second row (After) a number that equals it, it is changed to itself. Deletion. When a number in Before has `0' below it, it is deleted. Addition. When a number in After has some structure in it that is not in the tree,then this structure is added to the tree. Substitution. When a number in Before has another number under it, the number under it (in After) is sustituted for it. The structure, that is, that the number stands for. Adjunction. Sister adjunction. When there are two numbers in After with `-' between them, then they (i.e. the nodes they represent) are to be made sister nodes. This usually occurs with a number in Before having another node adjoined to it, either to the left or the right, depending on their relative positions. Daughter adjunction. When two numbers in After are separated by `<' then the number on the left is to be made a daughter of the number on the right, and when they are separated by `>' then the opposite is true. Chomsky adjunction. When two numbers are separated by `+' then they under go a change whereby the first is copied, and this copy and the other node are made to be daughters of the original node. In the above description of the types of change possible, the point was made that the numbers in the Sc. are not moved themselves, but the nodes that they represent in the tree. Here, a node is something like NP, but I also refer to a node meaning a node, with all its dependent structure. When I use the word node in this sense, the former sense will be conveyed by the word `label'. In the programme itself, the usage is unfortunately ambiguous, and the reader is requested to keep this in mind. PROLAPSE Notation and Method. Notation. Written, as the programme is, in PROLOG, certain changes to the Linguistic notation have been required, but they are not extensive. As before, variables are represented with capital letters, but all non-variables use only lower case. In the Sc. code numbers have been represented with variables, but they are numbered sequentially in a similar fashion. Choice brackets {X,Y} have been replaced with [X,Y] (i.e. an ambedded list) and the T-rule itself is represented with lists, arranged so as to be familiar to the linguist. Indeed, everything the linguist could come into contact with has been designed to be as familiar to him or her as possible, for it would have to be were PROLAPSE to be used by non computer literate users. And many things the layman user would hope never to come across, deep in the programme, have been designed to model closely the ways and means he or she uses. As seen above, constituent structure is represented in a predicate/argument form, rather than the similar double label square bracket form usually used, eg pp[...]pp. A PROLAPSE T-rule can be seen in 7. As can be seen, in comparison with 6, every other feature is the same, and carries the same mening. 7). T-rule Sa: [s,[t,u],v,w,x,y,z] [X1,X2,X3,X4,X5,X6,X7] Sc: [X1+[sg],X2,X3>X7,0,X5-X6,X4,np(...)] Method. 1).If the Sa. matches the tree, continue. Else fail. 2).Take each node, made up of label and structure (filled in as the Sa. is matched to the tree) and prepare the tree by numbering the labels of it which are in the Sa. incrementally. 3).Taking each element of Before in turn, instantiate it to the numbered node (in the tree) to which it corresponds, and then instantiate each of After by removing code numbers from its Before part. 4).Taking one each of Before and After change the node in the tree that is the same as Before, to what is specified by After. The predicates in the programme that correspond to 1,2,3,4 here are: treefit (1) tree_prepare (2) tree_change instantiate (3) clean (3) change (4) Treefit. "Treefit" works using a depth-first search which checks breadth ways at each level in order to "calibrate" the first element of the Sa. to the tree. If the first element is a variable, the transformation fails. To "calibrate" the Sa. the first element, which like all the elements of the Sa. is a label of a node in the tree, or is a list of option labels, in which case one is chosen to be the label, is checked against all the tree's labels, except `s', the distinguished symbol, and if a label is found that is the same as the first element, then that label, with its structure (a node), is made the first element of a nodelist. The node list contains the elements of the Sa. with their structures filled in. The rest of the Sa. is "treefitted" by "matching" each subsequent label to the previously indentified node. If the element of the Sa. isn't a label but a variable or choice, then the same happens as with "calibrate". A label "matches" a node if there is another node which is "rightnex" to that node, the label of which corresponds to the element from the Sa. The node found is added to the nodelist and is the node with which "rightnex" operates next time. One node is "rightnex" to another if there are two immediate sisters, for example `x' and `y' here, in both w(....), and z(....), 8). w(a(b,c),x(p,q),y(m,n),z(x,y)) and the left node is a "rightdecendent" of the left sister, and the right node is a "leftdecendent" of the right sister. In 8 `b' and `a' are "leftdecendents" of `a', `c' and `a' are"rightdecendents" of `a'. 9). Node rightnex to Node x(p,q) a(b,c) x(p,q) c p a(b,c) p c Tree_prepare. To prepare the tree, a node at a time from the nodelist is looked for in the tree, using "update", and "switched" to a new node when found, which has as part of its label a number which uniquely identifies it, but is otherwise identical to the old node. "Update" and "switch" will be described later. To get unique identifying numbers, I have used "assert" to record in the database how many "switches" have been "done". When the call succeeds, this information is removed to enable the reuse of the same idea. Tree_change. This goal is satisfied by "instantiating" Before to a list of nodes, similar to nodelist, except that the tree has since been prepared with numbered labels, so "instantiate" makes the Xth element of Before the node in the tree with X as its code (i.e. part of its label). As the nodes have already been checked to be in the right alignment (they match the Sa.) and numbered accoringly, "find" is used to get `labelX' which it does using the same search pattern as "calibrate" and "sisters", utilising, as they do "try_all_trees". Originally I used "instantiate" rather than have "tree_prepare" return a new nodelist, like "treefit" because Before and After share variables, so once one is instantiated, so is the other -in the new order. The other reason was because a nodelist depends on the specific tree for its content, but I wanted it to be defined by variables beyond top level to make the T-rule familiar to the linguist. Unfortunately this instantiation of After as a `side-effect' was problematic in that the numbers were copied, and if After was to be used to change the tree ambiguities of code numbers would occur. For instance imagine that np1(...) were replaced with np2(...). When later np2(...) was to be deleted there would be two to choose from, and PROLAPSE working left to right would take the wrong one. I decided to still carry the "instantiation" of Before into After, but use a "clean" version of After in the "change" process by taking After and removing any numbers with "un_num", except for `0', which has special meaning. The tree is "changed" by taking the first element of Before and the first element of After, and "updating" the tree. The new tree is then recursively changed, using the rest of Before and After as guides. Because "update" is used to "tree_prepare" as well, I will describe it in detail here. Update. One tree is mapped onto another when the node being searched for is encountered in a list of daughters. That list is then "switched" to a new list, which is the same as the old bar the one node that was being searched for. Any node in the tree which is not the search node, or is not a decendent of the search node, is returned unchanged. "Update" uses "try_all_lists" to peel off the first node from a list and search it, treating it as a whole tree, for the node. An atom (i.e. not a node) is returned as itself. Switch. One list of nodes is switched to a new list, each node being copied bar the search node, which is altered in the way shown in XTRA_info. This can be "nodenum", when the node has its code number added to its label, or one of the elements of After, eg 9). np#refl(X4) 10). vp(...)>np(...) If this is the case, then the new node is constructed from the information given in XTRA_info. If it was just another node, say when the Sc. adds or substitutes a node, then it simply becomes the new node. Clearly, the advantage of using "update", "switch", and "try_all_lists" is that they can be called from any other part of the programme when predicates are needed to search through the tree to change one node to another. Note that "try_all_trees" is similar, as is "un_num_lists", but in a small programme like this is is not worth while combining them all, though it would be very easy, for they all require different nos. of arguments, and while I am not aware of what the conventions in A.I. are for things like this, I would imagine that extra unused arguments all over the place tend to complicate, rather than simplify, programmes, especially when read. What combinations I have done have simply been to show that it is simple enough to do. If the programme were to become bigger, I would probably combine them all into a tree mapping facility. Sample PROLAPSE runs. Full Run: current order= [passive]. This transformation uses a rule encoded from that in 11. 11). Passive. Sa: [np,t,pass,verb,np] [X1,X2,X3,X4,X5] Sc: [X5,X2,X3,X4,pp(prep(by),X1] ================================================================================ Do you want to test the ordering of the current package (option 1) or to change some aspects of the rule set for testing? (option 2).Choose the option you require by typing 1 or 2 followed by full-stop,return. |: 1. Do you require the current order? |: yes. Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np(det(the),noun(man)))) Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np(pronoun(it)))) Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past),pass(be,ppart)),verb(hit),np(det(the), noun(man)))) Result of passive: s(np(det(the),noun(man)),vp(aux(t(past),pass(be,ppart)),verb(hit), pp(prep(by),np(det(the),noun(man))))) Full Run: The transformation used is an encoded version of that in 12. 12). Reflexive. Sa. [np,aux,verb,np] [X1,X2,X3,X4] Sc. [X1,X2,X3,np#refl(X1)] ================================================================================ Do you want to test the ordering of the current package (option 1) or to change some aspects of the rule set for testing? (option 2).Choose the option you require by typing 1 or 2 followed by full-stop,return. |: 2. I'm sorry, this facility isn't available yet. Do you require the current order? |: no. Please type in the order of whichever transformations you choose like this: [trans1 trans2 trans3]. or [tran]. passive reflexive daughter chomsky sister |: [reflexive]. Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np(det(the),noun(man)))) Result of reflexive: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np#refl(np(det(the), noun(man))))) Exemplification of PROLAPSE's Ability for Structural Change. Sister Adjunction. 13). Sister. Sa. [verb] [X1] Sc. [X1-particle(down)] Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np(det(the),noun(man)))) Result of sister: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),particle(down),np(det(the), noun(man)))) Daughter Adjunction. 14). Daughter. Sa. [verb,np] [X1,X2] [X1>X2,0] Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np(det(the),noun(man)))) Result of daughter: s(vp(aux(t(past)),verb(hit,np(det(the),noun(man))),np(det(the),noun(man)))) As can be seen, this is an error, caused by "tree_prepare" because it cannot check that each node is "rightnex" to another as it goes along. This can be overcome by combining "treefit" and "tree_prepare", but only after the tree is checked as before, to stop any alterations happening that may later have proved to be inappropriate. Chomsky Adjunction. 14). Chomsky. Sa. [verb,np] [X1,X2] Sc. [X1+particle(down),X2] Deep Structure: s(np(det(the),noun(man)),vp(aux(t(past)),verb(hit),np(det(the),noun(man)))) Result of chomsky: s(np(det(the),noun(man)),vp(aux(t(past)),verb(verb(hit),particle(down)), np(det(the),noun(man)))) Conclusion. In this project I have attempted to computerise the basis of Chomsky's Standard Model of Transformational Grammar, and have, I believe been fairly successful at so doing. The major problem that I have not been able to get over is in the role of variables, for they only work within a transformation if they are null, and not if there was structure in the tree that they were supposed to match. As there is a working version of T.G. encoded here, I hope to first solve the variable problem, and make sure the transformations work under all possible circumstances, and then make the programme a practical tool for testing rules on a given Deep Structure. The main features that I have not had enough time to consider lie in rules for embedded sentences, and from there, the cycle. Other features missing include conditions, orthographic rules, and any lexical insertion rules: but after all, these must follow the implementation of the basic machinery, which I have managed to do in this project. Bibliography. John Lyons(1981) Language and Linguistics C.U.P Cambridge E.K.Brown and J.E.Miller(1982) Syntax:Generative Grammar Hutchinson London T.Winograd(1983) Language as a Cognitive Process Volume 1: Syntax Addison-Wesley London J.Friedman(1972) Mathematical & Computational Models of Transformational Grammar. In Machine Intelligence 7); eds Meltzer & Michie ------ ----- :- reconsult(ai_tg). :- reconsult(ai_dcg). :- reconsult(utils). /* Transformational Grammar Programme */ /* """""""""""""""""""""""""""""""""" */ /* ..........James Scobbie.......... */ /* ~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~ */ /* artificial intelligence department */ /* """""""""""""""""""""""""""""""""" */ :-op(500,yfx,[#]). go:-banner,choose(Namelist),!,s(Deep,_,_),show(Deep), do(Deep,Namelist,Surface). banner:-line(0),nl, printstring("Do you want to test the ordering of the current"),nl, printstring("package (option 1) or to change some aspects of"),nl, printstring("the rule set for testing? (option 2).Choose the"),nl, printstring("option you require by typing 1 or 2 followed by"),nl, printstring("full-stop,return."),nl, read_in(X),reply(X). reply([1,.]):-!,nl. reply(X):-printstring("I'm sorry, this facility isn't available yet."),nl. show(Deep):-nl, printstring("Deep Structure:"),nl, print(Deep),nl. choose(Namelist):- printstring("Do you require the current order?"),nl, read_in(X), chekchooz(X,Namelist). chekchooz(X,Namelist):- member(yes,X), current(Namelist). chekchooz(X,Namelist):- bchooz(Namelist). bchooz(Namelist):- nl,printstring("Please type in the order of whichever"), nl,printstring("transformations you choose like this:"), nl,printstring("[trans1 trans2 trans3]. or [tran]."),nl, shownames, read_in(X), append(Namelist,[.],X),!. shownames:- name(X), X=..[Name|_], print(Name),nl, fail. shownames:-!. do(Tree,[],Tree). do(Deep,[Trans1|Restrans],Surface):- transform(Trans1,Deep,Worstr), nl,printstring("Result of "), print(Trans1),nl, print(Worstr), do(Worstr,Restrans,Surface). transform(Name,Structure,Result):- details(Name,Sa,Sc1,Sc2), treefit(Sa,Nodelist,Structure), assert(done(0)), tree_prepare(Nodelist,Structure,Pre_change), tree_change(Sc1,Sc2,Pre_change,Result),!. treefit([Firstsa|Restsa],[Firstnode|Restnodes],Tree):- calibrate(Firstsa,Firstnode,Tree), match(Restnodes,Restsa,Firstnode,Tree),!. calibrate(Salist,Firstnode,Tree):- nonvar(Salist), is_list(Salist), member(Sa,Salist), Sa\==[], calibrate(Sa,Firstnode,Tree). calibrate(Firstsa,Firstnode,Tree):- simple_sa(Firstsa), functor(Tree,_,Arity), between(1,Arity,Num), arg(Num,Tree,Firstnode), functor(Firstnode,Firstsa,_). calibrate(Firstsa,Firstnode,Tree):- simple_sa(Firstsa), Tree=..[F|Subtrees], try_all_trees(Firstsa,Firstnode,Subtrees,calibrate). match([],[],_,_). match(Nodes,[Salist|Restsa],Thisnode,Tree):- nonvar(Salist), is_list(Salist), member(Sa,Salist), Sa\==[], match(Nodes,Sa,Thisnode,Tree). match(Nodes,[Savar|Restsa],Thisnode,Tree):- var(Savar), match(Nodes,Restsa,Thisnode,Tree). match([Nextnode|Restnodes],[Savar|Restsa],Thisnode,Tree):- var(Savar), rightnex(Savar,Nextnode,Thisnode,Tree), match(Restnodes,Restsa,Nextnode,Tree). match([Nextnode|Restnodes],[Sa|Restsa],Thisnode,Tree):- simple_sa(Sa), rightnex(Sa,Nextnode,Thisnode,Tree), match(Restnodes,Restsa,Nextnode,Tree). rightnex(Sa,Nextnode,Thisnode,Tree):- sisters(Right,Left,Tree), rightdecendent(Thisnode,Left), leftdecendent(Nextnode,Right), functor(Nextnode,Sa,_). sisters(Right,Left,Tree):- functor(Tree,_,Arity), between(1,Arity,Num), arg(Num,Tree,Left), Newnum is Num+1, arg(Newnum,Tree,Right). sisters(Right,Left,Tree):- Tree=..[_|Subtrees], try_all_trees(Right,Left,Subtrees,sisters). leftdecendent(X,X). leftdecendent(Lonode,Hinode):- arg(1,Hinode,Left_daughter), leftdecendent(Lonode,Left_daughter). rightdecendent(X,X). rightdecendent(Lonode,Hinode):- functor(Hinode,_,Arity), arg(Arity,Hinode,Right_daughter), rightdecendent(Lonode,Right_daughter). tree_prepare([],Tree,Tree):-retractall(done,1),!. tree_prepare([Node1|Restnodes],Oldtree,Newtree):- update(nodenum,Node1,Wortree,Oldtree), tree_prepare(Restnodes,Wortree,Newtree). tree_change(Before,After,Pre_change,Post_change):- assert(done(0)), instantiate(Before,Pre_change), clean(After,Clean_after), change(Before,Clean_after,Pre_change,Post_change). instantiate([],Tree):- retractall(done,1),!. instantiate([Firstnode|Restnodes],Tree):- retract(done(X)), Y is X+1, find(Y,Firstnode,Tree), assert(done(Y)), instantiate(Restnodes,Tree). clean([],[]):-!. clean([0|T],[0|Newt]):- clean(T,Newt),!. clean([Node|Rest],[Newnode|Newrest]):- un_num(Node,Newnode), clean(Rest,Newrest). change([],[],Tree,Tree). change([Bef|Restbef],[Af|Restaf],Oldtree,Newtree):- update(Af,Bef,Worstr,Oldtree), change(Restbef,Restaf,Worstr,Newtree). update(_,_,X,X):- atomic(X). update(XTRA_info,Node,Newtree,Oldtree):- Oldtree=..[F|Subtrees], not(member(Node,Subtrees)), try_all_lists(Node,Newsubtrees,Subtrees,XTRA_info), Newtree=..[F|Newsubtrees]. update(XTRA_info,Node,Newtree,Oldtree):- Oldtree=..[F|Oldlist], member(Node,Oldlist), switch(XTRA_info,Node,Oldlist,Newlist), Newtree=..[F|Newlist]. switch(_,_,[],[]). switch(XTRA_info,Node,[H|T],[H|Newt]):- Node\==H, switch(XTRA_info,Node,T,Newt). switch(nodenum,Node,[Node|T],[Newnode|Newt]):- nodenum(Node,Newnode), switch(XTRA_info,Node,T,Newt). switch(0,Node,[Node|T],New):- switch(0,Node,T,New). switch(XTRA_info,Node,[Node|T],[Newnode,Sis|Newt]):- XTRA_info=..[-,Newnode,Sis], switch(XTRA_info,Node,T,Newt). switch(XTRA_info,Node,[Node|T],[Newnode|Newt]):- XTRA_info=..[>,Mum,Daut], Mum=..[F|List], append(List,[Daut],Newlist), Newnode=..[F|Newlist], switch(XTRA_info,Node,T,Newt). switch(XTRA_info,Node,[Node|T],[Newnode|Newt]):- XTRA_info=..[<,Daut,Mum], Mum=..[F|List], append([Daut],List,Newlist), Newnode=..[F|Newlist], switch(XTRA_info,Node,T,Newt). switch(XTRA_info,Node,[Node|T],[Newnode|Newt]):- XTRA_info=..[+,A,B], functor(A,F,_), Newnode=..[F,A,B], switch(XTRA_info,Node,T,Newt). switch(Newnode,Node,[Node|T],[Newnode|Newt]):- Newnode\==nodenum, Newnode\==0, Newnode=..[F|_], not(member(F,[-,+,>,<])), switch(Newnode,Node,T,Newt). nodenum(X,Y):- X=..[F|List], retract(done(D)), E is D+1, E=<20, assert(done(E)), F\==[], name(F,One), name(E,Num), append(One,Num,Two), Two\==[], name(Newf,Two), Y=..[Newf|List]. un_num(Node,Newnode):- Node=..[F|List], F\==[], name(F,Chars), append(Newchars,Code,Chars), Code\==[], name(Num,Code), integer(Num), Newchars\==[], name(Newf,Newchars), Newnode=..[Newf|List], Newnode\==Node,!. un_num(Node,Newnode):- Node=..[F|List], un_num_lists(List,Newlist), Newnode=..[F|Newlist]. un_num(Node,Node):- atomic(Node), name(Node,Chars), lastelement(Chars,X), name(Nonint,X), not(integer(Nonint)). find(Num,Node,Tree):- functor(Tree,_,Arity), between(1,Arity,X), arg(X,Tree,Node), checkout(Num,Node). find(Num,Node,Tree):- Tree=..[F|Subtrees], try_all_trees(Num,Node,Subtrees,find). checkout(Num,Node):- functor(Node,F,_), name(F,List), name(Num,[Weelist]), member(Weelist,List). try_all_trees(B,A,[H|_],Pred):- Call=..[Pred,B,A,H], call(Call). try_all_trees(B,A,[_|T],Pred):- try_all_trees(B,A,T,Pred). try_all_lists(Node,[],[],_). try_all_lists(Node,[H|T],[New_h|Newt],XTRA_info):- update(XTRA_info,Node,H,New_h), try_all_lists(Node,T,Newt,XTRA_info). un_num_lists([],[]):-!. un_num_lists([H|T],[New_h|Newt]):- un_num(H,New_h), un_num_lists(T,Newt). name(passive([np,t,pass,verb,np], [X1,X2,X3,X4,X5], [X5,X2,X3,X4,pp(prep(by),X1)])). name(reflexive([np,aux,verb,np], [X1,X2,X3,X4], [X1,X2,X3,np#refl(X4)])). name(daughter([verb,np], [X1,X2], [X1>X2,0])). name(chomsky([verb,np], [X1,X2], [X1+particle(down),X2])). name(sister([verb], [X1], [X1-particle(down)])). current([passive]). /* UTILITIES */ /* """"""""" */ printstring([]):-!. printstring([H|T]):-put(H),printstring(T). read_in([W|Ws]):-get0(C),readword(C,W,C1),restsent(W,C1,Ws). restsent(W,_,[]):-lastword(W),!. restsent(W,C,[W1|Ws]):-readword(C,W1,C1),restsent(W1,C1,Ws). readword(C,W,C1):-singlec(C),!,name(W,[C]),get0(C1). readword(C,W,C2):-in_word(C,NewC),!,get0(C1),restword(C1,Cs,C2),name(W,[NewC|Cs]). readword(C,W,C2):-get0(C1),readword(C1,W,C2). restword(C,[NewC|Cs],C2):-in_word(C,NewC),!,get0(C1),restword(C1,Cs,C2). restword(C,[],C). singlec(44). singlec(59). singlec(58). singlec(63). singlec(33). singlec(46). in_word(C,C):-C > 96,C < 123. in_word(C,L):-C > 64,C < 91,L is C+32. in_word(C,C):-C > 47,C < 58. in_word(39,39). in_word(45,45). lastword('.'). lastword('!'). lastword('?'). newline(0):-!. newline(X):-nl,Z is X-1,newline(Z). line(80):-!. line(X):-put("="),Y is X+1,line(Y). member(X,[X|_]). member(X,[_|Y]):-member(X,Y). last_element([El|[]],El):-!. last_element([_|Tail],El):-last_element(Tail,El). append([],L,L). append([X|L1],L2,[X|L3]):-append(L1,L2,L3). details(Name,Sa,Sc1,Sc2):- X=..[Name,Sa,Sc1,Sc2], call(name(X)). num(1). num(X):-num(Y), X is Y+1. between(Upper,Upper,Upper):-!. between(Lower,Upper,Lower):- Lowernp(NP),vp(VP). vp(vp(AUX,VERB,NP))-->aux(AUX),verb(VERB),np(NP). np(np(DET,NOUN))-->det(DET),noun(NOUN). np(np(PRONOUN))-->pronoun(PRONOUN). aux(aux(T))-->t(T). aux(aux(T,PASS))-->t(T),pass(PASS). pass(pass(be,ppart))-->[be],[ppart]. t(t(past))-->[past]. det(det(the))-->[the]. noun(noun(man))-->[man]. pronoun(pronoun(it))-->[it]. verb(verb(hit))-->[hit].