1 {------------------------------------------------------------------------------ 2 KNOWLEDGE 3 4 Knowledge, in the form of sentences and phrases with variables in them, is 5 represented using a tree structure. Simple parsers are provided for rules, 6 goals, relations and nouns. Functions are provided for converting a text file 7 into a table of definitions and for accessing the table. 8 ------------------------------------------------------------------------------} 9 10 module Knowledge where 11 import Result 12 import Table 13 import List(nub)--1.3 14 15 -- The type `Phrase' is a tree-like data structure for storing sentences and 16 -- phrases. A phrase is usually a term consisting of a word with a list of 17 -- subphrases. Variables are picked out separately as they have a special role, 18 -- and a function is provided for extracting a duplicate-free list of the names 19 -- of the variables in a phrase. Variable names start with capital letters. A 20 -- single type is used rather than separate types for rules, goals, relations 21 -- and so on to make it easier to write the matching and searching modules. 22 23 data Phrase = Term String [Phrase] | Var String 24 25 vars p = nub (names p) where 26 names (Var x) = [x] 27 names (Term x ps) = concat [names p | p <- ps] 28 29 -- The display function `showPhrase' assumes that the only phrases are 30 -- variables, nouns, and pairs of subphrases with joining words between them. 31 32 showPhrase (Var x) = x 33 showPhrase (Term x []) = x 34 showPhrase (Term op [p1,p2]) = 35 showPhrase p1 ++ " " ++ op ++ " " ++ showPhrase p2 36 37 -- Each parser takes a list of words and returns a Phrase. The parsers for 38 -- rules, goals and relations involve finding the joining word and the two 39 -- lists of words on either side with `split', and then parsing the two lists. 40 -- A rule is a relation and a goal joined by `if'. A goal is a collection of 41 -- relations joined by `and' and `or', with `and' binding tighter. A relation 42 -- is two nouns joined by a verb, and a noun is a word, perhaps preceded by 43 -- `a', `an' or `the' for readability. These parsers are neither very general 44 -- (no brackets, for instance) nor very efficient, nor do they detect errors. 45 46 rule ws = split ws relation "if" goal 47 48 goal ws 49 | elem "or" ws = split ws goal "or" goal 50 | elem "and" ws = split ws goal "and" goal 51 | otherwise = relation ws 52 53 relation ws = 54 split ws noun verb noun where 55 verb = head [w | w<-ws, elem w verbs] 56 verbs = ["is","describes","has","can","eats"] 57 58 noun [a,x] | elem a ["a","an","the"] = noun [a++" "++x] 59 noun [x] | ('A' <= head x) && (head x <= 'Z') = Var x 60 noun [x] = Term x [] 61 62 split ws f op g = 63 Term op [f lhs, g rhs] 64 where 65 lhs = takeWhile (/=op) ws 66 rhs = tail (dropWhile (/=op) ws) 67 68 -- The `definitions' function takes a list of text lines and converts it into a 69 -- table of definitions. Each entry is a verb, together with the rules which 70 -- are define that verb. Each verb is either completely defined in the table 71 -- (eg `is', `describes') or is completely undefined so that the user has to be 72 -- asked (eg `has', `eats'). The `relevant' function extracts from the table 73 -- the list of rules which are relevant to a given relation. 74 75 definitions ls = 76 updateList newTable [(v, def v) | v<-verbs] where 77 def v = [r | r<-rs, verb r == v] 78 verbs = nub [verb r | r<-rs] 79 verb (Term "if" [Term v ns, g]) = v 80 rs = [rule (words l) | l<-ls] 81 82 relevant defs (Term v ns) = 83 if fails lookup then [] else answer lookup where 84 lookup = find defs v