{------------------------------------------------------------------------------ EXPERT SYSTEM This prototype expert system program uses the modules `result.g', `table.g', `knowledge.g', `match.g' and `search.g'. The main program reads in the file `animals', treats the first line as the main goal to be solved, and converts the remaining lines into the table of definitions representing the permanent knowledge about the problem area. The program then solves the main goal and displays the questions and solutions to the user, using the answers to the questions to continue the search for solutions. Each answer should be `yes' or `no'. After each solution, the user is asked whether the solution is adequate or whether the search should be continued for alternative solutions. ------------------------------------------------------------------------------} module Main where import Result import Table import Knowledge import Match import Search import IO hiding( try ) -- try is defined by Search import System--1.3 -- The `main' function reads in the data file before interacting with user. -- The `process' function takes the contents of the file and the input from the -- user and produces the output. It builds an initial goal and a definition -- table from the file contents, and an information table from the user's -- input, and calls the `solve' function. The list of questions and solutions -- from this call is stripped to remove duplicate questions, and displayed as -- output. The questions are also extracted and used to help build the -- information table which contains question-and-answer pairs. main = do prog <- getProgName args <- getArgs case args of [filename] -> getData filename [] -> getData "animals" _ -> hPutStr stderr ("Usage: " ++ prog ++ " datafile\n") getData filename = do contents <- readFile filename interact (process contents) {- OLD 1.2: main rs = GetProgName : GetArgs : let (r0:r1:rrs) = rs in case r1 of StrList [filename] -> getData filename rrs StrList [] -> getData "animals" rrs StrList args -> case r0 of Str prog -> [AppendChan stderr ("Usage: " ++ prog ++ " datafile\n")] Failure _ -> [] getData filename rs = ReadFile filename : let (r:rrs) = rs in case r of Failure ioerr -> [AppendChan stderr ("Unable to read file " ++ filename ++ "\n")] Str contents -> interact (process contents) rrs -} process contents input = "Solving: " ++ showPhrase problem ++ "\n" ++ display results (vars problem) replies where problem = goal (words (head (lines contents))) defs = definitions (tail (lines contents)) info = enterList newTable [(q,a) | (Question q, a) <- zip results replies] replies = [words l /= ["no"] | l <- lines input] db = (defs,info) newsoln = Soln newTable ['X' : show n | n<-[0..]] results = strip [] (solve db newsoln problem) -- The `strip' function takes the list of questions and solutions from the main -- call to `solve' and removes all but the first occurrence of each question, -- to make sure that the user is not asked the same question twice. The first -- argument is a list of the questions seen so far. strip qs [] = [] strip qs (Question q : rs) = if elem q qs then strip qs rs else Question q : strip (q:qs) rs strip qs (soln:rs) = soln : strip qs rs -- The display function displays a list of questions and solutions as a -- character stream. It also takes the list of variable names in the original -- goal to interpret solution environments using `showVars', and the list of -- answers from the user to determine whether to continue displaying more -- solutions. display [] xs as = "No (more) solutions\n" display (Question q : rs) xs as = "Is it true that " ++ q ++ "?\n" ++ display rs xs (tail as) display (Soln env vs : rs) xs as = "Solution: " ++ sol ++ ". More?\n" ++ etc where sol = showVars env xs etc = if as == [] || head as == False then "" else display rs xs (tail as) showVars env vs = foldr1 join (map showVar vs) where join x y = x ++ "; " ++ y showVar v = v ++ " = " ++ showPhrase (subst env (Var v))