Uses 911K of libraries. Click here for Pure Java version (5946L/31K).
1 | !7 |
2 | |
3 | cmodule PhilosophyBot extends DynPrintLog { |
4 | transient S program = [[ |
5 | "memory" |
6 | |
7 | memory can mean RAM |
8 | RAM has a size |
9 | I have RAM |
10 | |
11 | input is x & x can mean y => pretend (input is y) |
12 | |
13 | input is x => activate facts containing x |
14 | |
15 | I have x => Ask something about (my x) |
16 | |
17 | I have x => (my x) exists |
18 | |
19 | x has a y & (my x) exists => (my x) has a y |
20 | |
21 | assume x => x |
22 | |
23 | // General patterns in flight now: |
24 | // my * |
25 | // Ask something about * |
26 | // pretend * |
27 | // input is * |
28 | // (and more) |
29 | |
30 | Procedures |
31 | ---------- |
32 | |
33 | Ask something about x => proc { |
34 | if (x exists): |
35 | ask (what is x?) |
36 | else: |
37 | ask (does x exist?) |
38 | for (y | x has a y): |
39 | assume ((the y of x) exists) |
40 | ask something about (the y of x) |
41 | } |
42 | |
43 | the answer to x is y => the answer to x is known |
44 | |
45 | ask x & the answer to x is known => don't (ask x) |
46 | |
47 | Ask x => proc { |
48 | print x |
49 | on input: |
50 | if (input is a valid answer to x): |
51 | store (the answer to x is input) |
52 | } |
53 | |
54 | (x exists) is a valid answer to (does x exist) |
55 | (x doesn't exist) is a valid answer to (does x exist) |
56 | (x is y) is a valid answer to (what is x) |
57 | ]]; |
58 | |
59 | srecord LogicRule(lhs, rhs) {} |
60 | srecord And(a, b) {} |
61 | srecord If(condition, thenBlock, elseBlock) {} |
62 | srecord For(var, condition, body) {} |
63 | |
64 | transient Set<S> facts = linkedCISet(); |
65 | transient Set<S> originalFacts; |
66 | transient new LinkedHashSet<LogicRule> logicRules; |
67 | transient new AllOnAll<LogicRule, S> rulesOnFacts; |
68 | transient new LS proceduresToRun; |
69 | |
70 | transient Set<S> vars = litciset("x", "y"); |
71 | |
72 | void addLogicRule(LogicRule rule) { |
73 | if (logicRules.add(rule)) { |
74 | print("Got logic rule", rule); |
75 | rulesOnFacts.newA(rule); // to combine it with the facts |
76 | } |
77 | } |
78 | |
79 | void addFact(S fact) { |
80 | fact = trim(fact); |
81 | if (empty(fact)) ret; |
82 | fact = tok_deRoundBracket(fact); |
83 | // Check if it's a procedure |
84 | LS tok = javaTokWithBrackets(fact); |
85 | if (countCodeTokens(tok) == 2 && eqic(getCodeToken(tok, 0), "proc") |
86 | && isCurlyBracketed(getCodeToken(tok, 1))) { |
87 | // It's a procedure! |
88 | S proc = uncurly_keepSpaces(getCodeToken(tok, 1)); |
89 | if (proceduresToRun.add(proc)) { |
90 | print("Got procedure:"); |
91 | print(indentx("> ", proc)); |
92 | } |
93 | } |
94 | else // It's a fact, not a procedure |
95 | if (facts.add(fact)) { |
96 | print("Got fact: " + fact); |
97 | rulesOnFacts.newB(fact); // to combine it with the rules |
98 | } |
99 | } |
100 | |
101 | void runProcedure(S proc) { |
102 | print("Running procedure."); |
103 | L commands = parseProcedure(proc); |
104 | runParsedProcedure(commands); |
105 | } |
106 | |
107 | void runParsedProcedure(L commands) { |
108 | for (O cmd : commands) { |
109 | if cmd is If(O condition, O thenBlock, O elseBlock) { |
110 | O blockToRun = checkCondition(condition) ? thenBlock : elseBlock; |
111 | runParsedProcedure(ll(blockToRun)); |
112 | } else if cmd is For(O var, O condition, O body) { |
113 | // make a new logic rule and add it |
114 | // assume the variable is globally declared as a variable |
115 | addLogicRule(new LogicRule(condition, "proc {\n" + body + "\n}")); |
116 | } else if (cmd cast S) { |
117 | addFact(cmd); |
118 | } else if (cmd != null) |
119 | fail("Unimplemented command: " + cmd); |
120 | } |
121 | } |
122 | |
123 | bool checkCondition(O o) { |
124 | ret o instanceof S && contains(facts, (S) o); |
125 | } |
126 | |
127 | L parseProcedure(S proc) { |
128 | //printStruct(proc); |
129 | proc = withoutLinesEmptyAfterTrim(proc); |
130 | //printStruct(proc); |
131 | proc = autoUnindent(proc); |
132 | //printStruct(proc); |
133 | print(indentx("> ", proc)); |
134 | |
135 | LS l = groupPythonStyleIndents(proc); |
136 | pnl("unpythonized ", l); |
137 | |
138 | new L out; |
139 | for i over l: { |
140 | S s = l.get(i); |
141 | LS tok = javaTokWithBrackets(s); |
142 | if (eqic(firstCodeToken(tok), "if")) { |
143 | assertEquals(s, ":", getCodeToken(tok, 2)); |
144 | out.add(new If(deRoundBracket(getCodeToken(tok, 1)), |
145 | joinSubList(tok, 3*2), null)); |
146 | } else if (eqic(firstCodeToken(tok), "else")) { |
147 | O last = last(out); |
148 | if (!last instanceof If) fail("Else without if"); |
149 | assertEquals(s, ":", getCodeToken(tok, 1)); |
150 | ((If) last).elseBlock = joinSubList(tok, 2*2); |
151 | } else if (eqic(firstCodeToken(tok), "for")) { |
152 | assertEquals(s, ":", getCodeToken(tok, 2)); |
153 | S cond = getCodeToken(tok, 1); |
154 | // cond looks like: "(y | x has a y)" |
155 | cond = deRoundBracket(cond); |
156 | LS tok2 = javaTok(cond); |
157 | assertEquals(cond, "|", getCodeToken(tok2, 1)); |
158 | S var = assertIdentifier(cond, getCodeToken(tok2, 0)); |
159 | S actualCondition = trimJoinSubList(tok2, 2*2+1); |
160 | out.add(new For(var, actualCondition, joinSubList(tok, 3*2))); |
161 | } else |
162 | out.add(s); |
163 | } |
164 | pnl("Parsed procedure ", out); |
165 | ret out; |
166 | } |
167 | |
168 | O splitAtAmpersand2(S s) { |
169 | LS l = tok_splitAtAmpersand(s); |
170 | if (l(l) == 1) ret s; |
171 | ret new And(first(l), splitAtAmpersand2(join(" & ", dropFirst(l)))); |
172 | } |
173 | |
174 | void applyLogicRuleToFact(LogicRule rule, S fact) { |
175 | O lhs = rule.lhs, rhs = rule.rhs; |
176 | O cond, remaining = null; |
177 | if lhs is And(O a, O b) { |
178 | cond = a; |
179 | remaining = b; |
180 | } else |
181 | cond = lhs; |
182 | |
183 | // now we match the condition with the fact |
184 | SS map = gazelle_zip((S) cond, fact); |
185 | if (map == null) ret; // no match |
186 | print("gazelle zip => " + map); |
187 | |
188 | // are only variables changed? |
189 | if (!allKeysAreInSet(map, vars)) |
190 | ret /*with print("Non-variable changes, exiting")*/; |
191 | |
192 | // Now we have a proper mapping with the keys being variables! |
193 | print("Match."); |
194 | |
195 | // drop round brackets |
196 | // XXX? map = mapValues tok_deRoundBracket(map); |
197 | |
198 | // Apply mapping to right hand side |
199 | S rhs_replaced = join(replaceCodeTokensUsingMap(javaTok((S) rhs), map)); |
200 | print(+rhs_replaced); |
201 | |
202 | if (remaining == null) { |
203 | // Add as fact |
204 | addFact(rhs_replaced); |
205 | } else { |
206 | // Apply mapping to remaning condition |
207 | S remaining_replaced = join(replaceCodeTokensUsingMap(javaTok((S) remaining), map)); |
208 | addLogicRule(new LogicRule(remaining_replaced, rhs_replaced)); |
209 | } |
210 | } |
211 | |
212 | start-thread { |
213 | // split into paragraphs and unindent |
214 | |
215 | LS paragraphs = map autoUnindent(map rtrim(splitAtEmptyLines(program))); |
216 | print("Got " + n2(paragraphs, "parapraph")); |
217 | |
218 | // print the parapraphs |
219 | print(joinWithEmptyLines(map(s -> indentx("> ", s), paragraphs))); |
220 | |
221 | // throw away comment-only and quoted paragraphs (assume it's a title) |
222 | LS paragraphs2 = antiFilter(paragraphs, s -> |
223 | isSingleLine(trim(s)) && isQuoted(trim(s)) || countJavaTokens(s) == 0 |
224 | || endsWith(rtrim(s), "----")); |
225 | print("Got " + n2(paragraphs2, "filtered paragraph")); |
226 | print(joinWithEmptyLines(map(s -> indentx("> ", s), paragraphs2))); |
227 | |
228 | // find fact paragraphs |
229 | |
230 | print(map allLinesAreUnindented(paragraphs2)); |
231 | Pair<LS> p1 = filterAntiFilter(s -> |
232 | !isSingleLine(trim(s)) && allLinesAreUnindented(s), paragraphs2); |
233 | LS multiFactParagraphs = p1.a, paragraphs3 = p1.b; |
234 | |
235 | for (S para : multiFactParagraphs) |
236 | for (S s : tlft(para)) |
237 | addFact(s); |
238 | |
239 | // find logic rules |
240 | |
241 | new LS paragraphs4; |
242 | for (S para : paragraphs3) { |
243 | PairS p = splitAtDoubleArrow_pair(para); |
244 | if (p == null) continue with paragraphs4.add(para); |
245 | addLogicRule(new LogicRule(splitAtAmpersand2(p.a), splitAtAmpersand2(p.b))); |
246 | } |
247 | |
248 | pnlStruct("Unparsed", paragraphs4); |
249 | originalFacts = cloneSet(facts); |
250 | |
251 | // Parsing done, now THINK |
252 | |
253 | think(); |
254 | } |
255 | |
256 | bool doSomeLogic() { |
257 | bool anyAction; |
258 | Pair<LogicRule, S> p; |
259 | while not null (p = rulesOnFacts.next()) { |
260 | set anyAction; |
261 | //print("Combination: " + p); |
262 | applyLogicRuleToFact(p.a, p.b); |
263 | } |
264 | ret anyAction; |
265 | } |
266 | |
267 | void think { |
268 | int round = 0; |
269 | bool anyAction; |
270 | |
271 | while (round++ < 100) { |
272 | anyAction = false; |
273 | print("Logic round " + round); |
274 | while (doSomeLogic() && round++ < 100) set anyAction; |
275 | |
276 | for (S proc : getAndClearList(proceduresToRun)) { |
277 | set anyAction; |
278 | runProcedure(proc); |
279 | } |
280 | } |
281 | |
282 | // We're done logicking, so print all the facts gathered |
283 | |
284 | LS factsToPrint = listMinusList(facts, originalFacts); |
285 | pnlWithHeading("Facts I deduced", factsToPrint); |
286 | |
287 | // Print the actual output |
288 | |
289 | new LS output; |
290 | for (S fact : factsToPrint) { |
291 | LS tok = javaTokWithBrackets(fact); |
292 | if (countCodeTokens(tok) == 2 && eqic(getCodeToken(tok, 0), "print")) |
293 | // For the user, we print without all the round brackets |
294 | output.add(tok_dropRoundBrackets(getCodeToken(tok, 1))); |
295 | } |
296 | |
297 | pnlWithHeading("Bot Output", output); |
298 | } |
299 | } |
download show line numbers debug dex old transpilations
Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1025576 |
Snippet name: | Philosophy Bot 1 [OK] |
Eternal ID of this version: | #1025576/110 |
Text MD5: | 891dadfe5c6e8843c206b37fac399027 |
Transpilation MD5: | c00a4872d43174a71ed20bd94d9af748 |
Author: | stefan |
Category: | |
Type: | JavaX source code (Dynamic Module) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2019-10-05 22:46:17 |
Source code size: | 9003 bytes / 299 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 851 / 2449 |
Version history: | 109 change(s) |
Referenced in: | [show references] |