(DEFINE-FUNCTION Hamlet (intext-or-file &KEY (order 3) (samples 5) (using NIL)) "(HAMLET text-or-file [ORDER n] [SAMPLES n] [USING model]) - Makes a markov model given training text - text-or-file may be a file name or a string of text - The order of the model is 3 unless ORDER is specified - Text generated by the model is displayed, the number of units determined by the value of SAMPLE - (LET* ((intext (ENSURE-LIST (COND ((LISTP intext-or-file) intext-or-file) ((NOT (STRINGP intext-or-file)) (ERROR "Hamlet requires either text or a file-name")) ((< (LENGTH intext-or-file) 32) (FILE-TO-STRING intext-or-file)) (T intext-or-file)))) (boundary-char (CODE-CHAR 255)) (boundary (MAKE-STRING order :INITIAL-ELEMENT boundary-char)) (model-counts NIL) (model using)) ;; COUNT TEXT (if model not provided) (WHEN (NOT model) (FOR-EACH text IN intext AS bounded-text = (CONCATENATE 'STRING boundary text) DO (FOR-EACH start FROM 1 TO (- (LENGTH bounded-text) order 1) AS end = (+ start order -1) AS key = (GET-ELEMENT start TO end FROM bounded-text) AS target = (GET-STRING-ELEMENT (+ end 1) FROM bounded-text) DO (INCREMENT model-counts(key target)))) ;; MAKE MODEL (FOR-EACH key IN (LABELS-OF model-counts DIMENSION 1) AS sum = (FOR-EACH target IN (LABELS-OF-SLICE model-counts(key)) SUM (VALUE-OF model-counts(key target))) DO (FOR-EACH target IN (LABELS-OF-SLICE model-counts(key)) DO (ASSIGN model(key target) = (/ (VALUE-OF model-counts(key target)) sum))))) ;; MAKE OUTPUT TEXT (LOOP WITH iteration = 1 WITH word = boundary WHILE (NOT (> iteration samples)) AS p = (RANDOM 1.0) AS letter = (FOR-EACH target IN (LABELS-OF-SLICE model (word)) AS target-p = (VALUE-OF model(word target)) WHEN (> target-p p) RETURN target DO (ASSIGN p = (- p target-p)) FINALLY (RETURN target)) COLLECT letter INTO output-letters DO (ASSIGN word = (JOIN (LIST (GET-ELEMENTS 2 TO 'end FROM word) letter))) (IF-TRUE (EQUAL letter ".") THEN (INCREMENT iteration)) FINALLY (DISPLAY (JOIN output-letters))) (IF (NOT using) model)))