;Interacting with SNePS ; ; The GATN in this section accepts the same fragment of English as the one ;in the previous section, but, instead of building and returning parse trees, ;it builds a SNePS network representing the information in the statements and ;answers the questions. The statements are echoed and the questions are ;answered in English generated by the generation part of this GATN. ;;; First, the SNePS relations used in the GATN are defined. (^^ define agent act object propername member class lex) ;;; Next, a global variable, a global constant, and two functions are defined. (^^ defvar *SaynBeforeVowels* nil "If true and the next word starts with a vowel, print 'n ' before that next word.") (^^ defconstant *vowels* '(#\a #\e #\i #\o #\u) "A list of the vowels.") ;;; The following two functions implement a "phonological" component ;;; that can be used to output words and phrases from arcs of the GATN. ;;; In this way, the beginning of the sentence can be uttered before ;;; the rest of the sentence has been composed. (^^ defun SayOneWord (word) "Prints the single WORD, which must be a string or a node. If the word is 'a', sets *SaynBeforeVowels*. If *SaynBeforeVowels* is set, then prints 'n ' before word/s if the first letter of word/s is a vowel." (check-type word (or string sneps:node)) (when (sneps:node-p word) (setf word (format nil "~A" word))) (when *SaynBeforeVowels* (when (member (char word 0) *vowels* :test #'char=) (format t "n")) (setf *SaynBeforeVowels* nil)) (when (string\= word "a") (setf *SaynBeforeVowels* t)) (format t " ~A" word)) (^^ defun say (word/s) "Prints the single word or the list of words. If the word is 'a', sets *SaynBeforeVowels*. If *SaynBeforeVowels* is set, then prints 'n ' before word/s if the first letter of word/s is a vowel." (if (listp word/s) (mapc #'SayOneWord word/s) (SayOneWord word/s))) ;;; The initial arc is used to make two SNePSUL variables, each of ;;; which holds a SNePS variable node. This results in a major ;;; efficiency gain over creating new SNePS variable nodes each time a ;;; question or an indefinite NP is parsed. (s (jump s1 t (or (* 'wh) ($ 'wh)) ; a SNePS variable to use for Wh questions (or (* 'x) ($ 'x)) ; a variable for indef NP's in questions )) (s1 (push ps t ; Parse a sentence, and send results to RESPOND (jump respond))) (ps (cat wh t ; A Wh question starts with "who" or "what". (setr agent (* 'wh)) ; set AGENT to a variable node. (setr mood 'question) (liftr mood) (to vp)) (push np t (sendr mood 'decl) ; The only acceptable statements are NP V [NP]. ; MOOD must be sent down, because an indefinite ; NP introduces a new individual in a statement, ; but must be treated as a variable to be found ; in a question. (setr agent *) ; set AGENT to parse of subject. (setr mood 'decl) (liftr mood) ; The state RESPOND must know whether ; it is echoing a statement or answering ; a question. (to vp))) (vp (cat v t ; Accept just a simple verb for this example, (setr act *) (to vp/v))) ; and ignore tense. (vp/v (push np t (sendr mood) (setr object *) ; Set OBJECT to parse of object. (to s/final)) (jump s/final t)) ; If no object. (s/final (jump s/end (overlap embedded t)) ; an embedded proposition (wrd "." (overlap mood 'decl) (to s/end)) (wrd "?" (overlap mood 'question) (to s/end))) (s/end (pop #!((assert agent ~(getr agent) ; Assert a top-level statement. act (build lex ~(getr act)) object ~(getr object))) (and (overlap mood 'decl) (nullr embedded))) (pop #2!((build agent ~(getr agent) ; Build an embedded statement. act (build lex ~(getr act)) object ~(getr object))) (and (getr embedded) (overlap mood 'decl))) (pop #!((deduce agent ~(getr agent) ; Use deduce to answer a question. act (build lex ~(getr act)) object ~(getr object))) (overlap mood 'question))) ;;; Notice in all three above arcs that if there is no object, ;;; (getr object) will evaluate to NIL, ;;; and the node will be built without an OBJECT arc. (np (wrd "that" t (to nomprop)) ; an embedded proposition (cat npr t (setr head (or ;; First try to find someone with the given name. #!((find (compose object- ! propername) ~(getr *))) ;; Otherwise, create one. #!((find object- (assert object #head propername ~(getr *)))))) (to np/end)) (cat art t (setr def (getf definite)) (to np/art))) (np/art (cat n (overlap def t) ; a definite np (setr head ; Find the referent. (Assume there is exactly one.) #!((find member- (deduce member *x class (build lex ~(getr *)))))) (to np/end)) (cat n (and (disjoint def t) (overlap mood 'decl)) (setr head ; Create a new referent. #!((find member- (assert member #hd class (build lex ~(getr *)))))) (to np/end)) (cat n (and (disjoint def t) (overlap mood 'question)) (setr head (* 'x)) ; a variable node. (to np/end))) (nomprop (push ps t ; Return the parse of embedded sentence. (sendr embedded t) (setr head *) (to np/end))) (np/end (pop head t)) ;;;;;;;;;;;;;;;;;;;;;; ;;; Generation Section ;;;;;;;;;;;;;;;;;;;;;; (respond (jump g (and (getr *) (overlap mood 'decl)) (say "I understand that")) ; Canned beginning of echo of statement. (jump g (and (getr *) (overlap mood 'question))) ; Answer of question. (jump g/end (nullr *) (say "I don't know."))) ; Question not answered. (g (rcall gnp (geta agent) (geta agent) ; Generate the agent as an np. reg (jump g/subj))) (g/subj (jump g/v (geta act) (say (verbize 'past ; For this example, always use past tense. (first (geta lex (geta act))))))) (g/v (rcall gnp (geta object) (geta object) ; Generate the object. reg (to g/end)) (to (g/end) (null (geta object)))) ; No object. (g/end (pop nil t)) (gnp (to (gnp/end) (geta propername (geta object-)) (say (geta propername (geta object-)))) ; Generate an npr. (to (gnp/end) (geta class (geta member-)) ; An indef np. (say (cons "a" #!((find (lex- class- ! member) ~(getr *)))))) (call g * (geta act) (say "that") * ; An embedded proposition (to gnp/end))) (gnp/end (pop nil t)) ; ;Here is a sample run using this grammar and the same lexicon as before: ; ;--> (parse) ; ATN parser initialization... ; Trace level = 0. ; Beginning at state 'S'. ; ; Input sentences in normal English orthographic convention. ; Sentences may go beyond a line by having a space followed by a ; To exit the parser, write ^end. ; ; : A dog bit John. ; I understand that a dog bit John ; Time (sec.): 0.25 ; ; : The dog slept. ; I understand that a dog slept ; Time (sec.): 1.884 ; ; : Mary believes that John likes the dog. ; I understand that Mary believed that John liked a dog ; Time (sec.): 0.4 ; ; : Mary studies Computer Science. ; I understand that Mary studied Computer Science ; Time (sec.): 0.2 ; ; : Mary used a computer. ; I understand that Mary used a computer ; Time (sec.): 0.233 ; ; : John saw a saw. ; I understand that John saw a saw ; Time (sec.): 0.217 ; ; : What bit John? ; a dog bit John ; Time (sec.): 0.167 ; ; : Who sleeps? ; a dog slept ; Time (sec.): 0.917 ; ; : Who studied? ; Mary studied ; Time (sec.): 0.167 ; ; : Who uses the computer? ; Mary used a computer ; Time (sec.): 0.267 ; ; : Who likes a dog? ; I don't know. ; Time (sec.): 0.167 ; ; : Who sees a saw? ; John saw a saw ; Time (sec.): 0.217 ; ;The SNePS network built as a result of this interaction is shown in ;Figure 8.2. Note especially that when definite noun phrases occurred in ;statements, they were represented by nodes that were already in the net ;because of previous indefinite noun phrases.