UNPKG

2.79 kBJavaScriptView Raw
1var fs = require('fs');
2var log = console.log;
3
4var kb = function() {
5 this.rules = [];
6 this.facts = {};
7 this.dict = {};
8}
9
10var kbp = kb.prototype;
11
12kbp.load = function(code) {
13 var lines = code.split(/[\.]+ ?/);
14 log("%j", lines);
15 for (var i in lines) {
16 if (lines[i].trim().length > 0)
17 this.addRule(lines[i]);
18 }
19 return this;
20}
21
22kbp.loadFile = function(file) {
23 var code = fs.readFileSync(process.cwd()+"/"+file, "utf8").replace(/\n/gi, "");
24 this.load(code);
25 return this;
26}
27
28kbp.isFact=function(term) {
29 if (term.length == 0)
30 return true;
31 return this.facts[term];
32}
33
34kbp.check = function(rule) {
35 for (var i in rule.terms) {
36 var term = rule.terms[i].trim();
37 if (this.isFact(term))
38 continue;
39 else
40 return false;
41 }
42 return true;
43}
44
45kbp.addFact = function(term) {
46 this.facts[term] = true;
47 log("addFact(%s)", term);
48}
49
50kbp.addRule = function(line) {
51 var m = line.match(/^([^<=]*)(<=(.*))?$/);
52 var head = (m[1]==null)?"":m[1].trim();
53 var terms= (m[3]==null)?"":m[3].trim().split(/&+/);
54 log("rule:head=%s terms=%j", head, terms);
55 var rule = { head:head, terms:terms, satisfy:false };
56 this.rules.push(rule);
57 this.dict[head] = { headHits: [rule], bodyHits:[] };
58}
59
60kbp.forwardChaining = function() {
61 do {
62 var anySatisfy = false;
63 for (var i in this.rules) {
64 var rule = this.rules[i];
65 if (!rule.satisfy) {
66 if (this.check(rule)) {
67 this.addFact(rule.head);
68 rule.satisfy = true;
69 anySatisfy = true;
70 }
71 }
72 }
73 } while (anySatisfy);
74 log("facts=%j", Object.keys(this.facts));
75 return this;
76}
77
78kbp.trySatisfy = function(goal) {
79 log("trySatisfy(%s)", goal);
80 var word = this.dict[goal];
81 if (word == null) return false;
82 var headHits = word.headHits;
83 for (var i in headHits) {
84 var rule = headHits[i];
85 if (rule.satisfy) {
86 this.addFact(goal);
87 return true;
88 } else {
89 var isSatisfy = true;
90 for (var ti in rule.terms) {
91 var term = rule.terms[ti];
92 var satisfy = this.trySatisfy(term);
93 if (!satisfy) isSatisfy = false;
94 }
95 rule.satisfy = isSatisfy;
96 if (isSatisfy) {
97 this.addFact(goal);
98 return true;
99 }
100 }
101 }
102 return false;
103}
104
105kbp.backwardChaining = function(goal) {
106 this.trySatisfy(goal);
107 log("facts=%j", Object.keys(this.facts));
108 return this;
109}
110
111kbp.query = function() {
112 var r = require('readline').createInterface(process.stdin, process.stdout);
113 r.setPrompt('?- ');
114 r.prompt();
115 var self = this;
116 r.on('line', function(line) {
117 var term = line.trim();
118 if (line === "exit") process.exit();
119 self.addFact(term);
120 self.forwardChaining();
121 r.prompt();
122 }).on('close', function() {
123 process.exit(0);
124 });
125 return this;
126}
127
128module.exports = kb;
\No newline at end of file