|
(defpackage :expressm (:export :m :m-all :fathom-init :make-stream-and-talk) (:use :common-lisp :theoretica :english :radiplex :fathomr :db :util)) (in-package :expressm) ;;;; Input and output to the fathomr. (defparameter *ind* 0 "Used to index words of a sentence passed in.") (defparameter *word-index* (make-hash-table) "Position of word in sentence.") (defparameter *last-phrase* nil "When we need to know what was said last.") (defstruct parse "Used to hold morphological info returned from server." constituents relations) (defun m (phrase &optional clear-context) ;; what do we need? ;; - what is the parse tree and semantic info from the parser? ;; - what is the result of their semantic interpretation? ;; - return the phrase that the result is the tree of ;; * therefore, we are assuming that the fathomr has instantiated a parse tree ;; from previous examples -- or is that done here? fathomr only semantics? ;; * how can we arrange a parse tree so that semantics lead to it? ;; componentization and selection of structure based on semantics? ;; how to componentize? source -function-> target instances, piecemeal formed ;; (each of which can be composed of an sft) ;; how the semantics of a parsed phrase fits within a context affects the ;; semantics of previous and subsequent phrases, and therefore the how the ;; semantics form (forming how to form) (unless (get-one (hashid *void*)) (init)) (if clear-context (fathom nil) (let ((parse (first (get-parses phrase)))) (multiple-value-bind (tree elements parts) (parse-tree (second (parse-constituents parse))) (let ((new (make-instance 'immediate :tree tree ; first is ROOT :semantics (append parts (define-relations (parse-relations parse)))))) (fathom new)))))) (defun clr () (clear-parent-cache) (clear-caches)) (defun m-all (filename &optional clear-context) (when clear-context (m "" T)) (mapcar #'m (load-from-file filename))) (defun init () (flet ((basic-add (nod ctx) (let ((added (add-one nod))) (setf (gethash (hashid nod) (proper ctx)) added)))) (mapcar #'(lambda (nod) (basic-add nod (inputs)) (basic-add nod (current-session))) *common-list*) (mapcar #'(lambda (nod) (basic-add nod (inputs)) (when (closurep nod) (set-all-parents )) (when (qnodep nod) (add-qnode nod))) *init-list*))) (defun parse-tree (tree) "Returns a parsed closure in non-cached form and syntactic elements." (let ((operator (first tree)) (remainder (rest tree)) (parsed (make-instance 'closure))) (if (stringp (car remainder)) (let* ((pos (cache-of (case-pos operator))) ; either a punctuation or a word (word (cache-of (car remainder))) (out (cache-of (make-instance 'connection :hashid nil :prev (hashid word) :curr (hashid *form*) :subs (hashid pos))))) (setf (root parsed) word) (setf (outs parsed) (list out)) (let ((wrapped (wrap out *POS*))) (set-all-parents wrapped) (values parsed '() (list wrapped)))) (let ((elements '()) (fwd nil) (constituent (case-constituent operator)) (speech '())) (dolist (one remainder) (multiple-value-bind (clo elem parts) (parse-tree one) (let ((out (make-instance 'connection :prev constituent :curr *bind* :subs clo)) (el (make-instance 'connection :prev constituent :curr *bind* :subs (root clo)))) (if (null fwd) (setf fwd (make-instance 'connection :prev clo)) (let ((el (make-instance 'connection :prev (root (prev fwd)) :curr *bind* ; correct? :subs (root clo)))) (setf (curr fwd) *bind*) (setf (subs fwd) clo) (push fwd (forwards parsed)) (setf fwd nil) (push el elements))) (setf speech (remove-duplicates (append speech parts))) (push out (outs parsed)) (push el elements) (setf elements (remove-duplicates (append elem elements)))))) (setf (root parsed) constituent) (setf (outs parsed) (reverse (outs parsed))) (setf (forwards parsed) (reverse (forwards parsed))) (values parsed elements speech))))) (defun parse-relation-word (str) (let ((parts (split str 9999 '(#\-)))) (if (> (list-length parts) 2) (let ((word (subseq str 0 (position #\- str :from-end T)))) (values word word (car (last parts)))) ; don't process hyphenated (let ((word (first parts))) (values word (get-word-root word) (second parts)))))) (defun define-relations (relations) (when relations (let* ((relation (first relations)) (dep (case-dependencies (first relation) (parse-relation-word (second relation)) (parse-relation-word (third relation))))) (if (connectionp dep) (let ((wrapped (wrap dep))) (set-all-parents wrapped) (cons wrapped (define-relations (rest relations)))) (define-relations (rest relations)))))) (defun wrap (out2 &optional targ) (let ((out1 (cache-of (make-instance 'connection :hashid nil :prev (prev out2) :curr (hashid *bind*) :subs (hashid (if targ targ *form*))))) (fwd (cache-of (make-instance 'connection :hashid nil :prev (hashid (if targ targ *form*)) :curr (hashid *free*) :subs (subs out2))))) (cache-of (make-closure nil (get-one (prev out2)) (list out1 out2) (list fwd))))) ; do we need to add-parents here? looks like they're added nowhere... (defun get-word-root (w) "Get root form of word from server." (let ((word-root (get-kb (concatenate 'string "=" w)))) (when word-root (setf word-root (caar word-root)) ;; filter out single letters (when (> (length word-root) 1) word-root)))) (defun get-parses (phrase) "Calls to external morphological server to get parses of the phrase." (let ((all-parses-in (get-kb (concatenate 'string "'" phrase "'"))) (all-parses-out '()) (current-parse nil)) (dolist (p all-parses-in) (cond ((string-equal (first p) "parse") (push current-parse all-parses-out) (setf current-parse nil)) (current-parse (push p (parse-relations current-parse))) ((null current-parse) (setf current-parse (make-parse)) (setf (parse-constituents current-parse) p)) (T nil))) (reverse all-parses-out))) (defun make-stream-and-talk (handle) (let ((stream (make-instance 'comm:socket-stream :socket handle :direction :io :element-type 'base-char))) (mp:process-run-function (format nil "talk ~D" handle) '() 'talk-on-stream stream))) (defun talk-on-stream (stream) (unwind-protect (loop for line = (read-line stream nil nil) while line do (format stream "'~A'~%" (fathom line)) (force-output stream)) (close stream))) ;(comm:start-up-server :function 'expressm:make-stream-and-talk :service 21212) (defun load-from-file (p) (let ((lines '())) (with-open-file (s p) (do ((l (read-line s) (read-line s nil 'eof))) ((eq l 'eof) "Reached end of file.") (unless (equal "" l) (push l lines)))) (reverse lines))) |