This commit is contained in:
Ingy döt Net 2013-10-27 22:24:23 +00:00
parent 6f050a029e
commit 776bba907c
3887 changed files with 59894 additions and 7280 deletions

View file

@ -0,0 +1,68 @@
;;; Keeps track of all our rules
(defclass markov ()
((rules :initarg :rules :initform nil :accessor rules)))
;;; Definition of a rule
(defclass rule ()
((pattern :initarg :pattern :accessor pattern)
(replacement :initarg :replacement :accessor replacement)
(terminal :initform nil :initarg :terminal :accessor terminal)))
;;; Parse a rule with this regular expression
(defparameter *rex->* (compile-re "^(.+)(?: |\\t)->(?: |\\t)(\\.?)(.*)$"))
;;; Create a rule and add it to the markov object
(defmethod update-markov ((mkv markov) lhs terminating rhs)
(setf (rules mkv) (cons
(make-instance 'rule :pattern lhs :replacement rhs :terminal terminating)
(rules mkv))))
;;; Parse a line and add it to the markov object
(defmethod parse-line ((mkv markov) line)
(let ((trimmed (string-trim #(#\Space #\Tab) line)))
(if (not (or
(eql #\# (aref trimmed 0))
(equal "" trimmed)))
(let ((vals (multiple-value-list (match-re *rex->* line))))
(if (not (car vals))
(progn
(format t "syntax error in ~A" line)
(throw 'fail t)))
(update-markov mkv (nth 2 vals) (equal "." (nth 3 vals)) (nth 4 vals))))))
;;; Make a markov object from the string of rules
(defun make-markov (rules-text)
(catch 'fail
(let ((mkv (make-instance 'markov)))
(with-input-from-string (s rules-text)
(loop for line = (read-line s nil)
while line do
(parse-line mkv line)))
(setf (rules mkv) (reverse (rules mkv)))
mkv)))
;;; Given a rule and bounds where it applies, apply it to the input text
(defun adjust (rule-info text)
(let* ((rule (car rule-info))
(index-start (cadr rule-info))
(index-end (caddr rule-info))
(prefix (subseq text 0 index-start))
(suffix (subseq text index-end))
(replace (replacement rule)))
(concatenate 'string prefix replace suffix)))
;;; Get the next applicable rule or nil if none
(defmethod get-rule ((markov markov) text)
(dolist (rule (rules markov) nil)
(let ((index (search (pattern rule) text)))
(if index
(return (list rule index (+ index (length (pattern rule)))))))))
;;; Interpret text using a markov object
(defmethod interpret ((markov markov) text)
(let ((rule-info (get-rule markov text))
(ret text))
(loop (if (not rule-info) (return ret))
(setf ret (adjust rule-info ret))
(if (terminal (car rule-info)) (return ret))
(setf rule-info (get-rule markov ret)))))

View file

@ -0,0 +1,27 @@
(defparameter
*rules1*
"# This rules file is extracted from Wikipedia:
# http://en.wikipedia.org/wiki/Markov_Algorithm
A -> apple
B -> bag
S -> shop
T -> the
the shop -> my brother
a never used -> .terminating rule")
;;; Lots of other defparameters for rules omitted here...
(defun test ()
(format t "~A~%" (interpret (make-markov *rules1*) "I bought a B of As from T S."))
(format t "~A~%" (interpret (make-markov *rules2*) "I bought a B of As from T S."))
(format t "~A~%" (interpret (make-markov *rules3*) "I bought a B of As W my Bgage from T S."))
(format t "~A~%" (interpret (make-markov *rules4*) "_1111*11111_"))
(format t "~A~%" (interpret (make-markov *rules5*) "000000A000000"))
)
(test)
I bought a bag of apples from my brother.
I bought a bag of apples from T shop.
I bought a bag of apples with my money from T shop.
11111111111111111111
00011H1111000
NIL