concepts. !include #1005279 // Str, concept, mergeStrs concept AThing { new Ref thing; *() {} *(Concept thing) { this.thing.set(thing); } } concept DefiniteThing {} static AThing aThing(S name) { ret uniqueConcept(AThing.class, "thing", concept(name)); } // "main" has a number of "part"s. concept HasMulti { new Ref main; new Ref part; } // "main" has exactly "count" "part"s. concept MultiCount { new Ref main; new Ref part; int count; } // "main" has a "part". concept HasA { new Ref main; new Ref part; } // "main" has "part". concept Has { new Ref main; new Ref part; } concept IsA { new Ref thing; new Ref type; } concept TheXOfY { new Ref x; new Ref y; } concept Question { S originalText; } concept OpenQuestion { new Ref question; } concept AnsweredQuestion { new Ref question; new Ref answer; } concept ConceptList { new RefL list; *() {} *(L l) { list.addAll_(l); } void addAll(L l) { list.addAll(l); } } concept HowManyAreIn extends Question { new Ref main; new Ref part; } concept DoesXHaveAY extends Question { new Ref x; new Ref y; } concept WhatDoesXHave extends Question { new Ref thing; } concept Yes {} concept No {} svoid processRulesMulti { for (int i = 0; i < 1000; i++) { long n = changes; processRules(); long n2 = changes; if (n2 > n) print(n(n2-n, "change") + " (concepts: " + countConcepts() + ")"); else ret; } print("safety limit reached (1000 iterations)"); } svoid answerQuestion(Question question, Concept answer) { cdelete(OpenQuestion.class, "question", question); uniqueConcept(AnsweredQuestion.class, "question", question, "answer", answer); } svoid answerQuestion(Question question, bool answer) { answerQuestion(question, uniqueConcept(answer ? Yes.class : No.class)); } svoid printConcepts { print(); for (Concept c : allConcepts()) printConcept(c); } svoid printConcept(Concept c) { print(renderConcept(c)); } static S renderConcept(Concept.Ref ref) { ret renderConcept(ref.get()); } static S renderConcept(Concept c) { new StringBuilder buf; if (c == null) buf.append("null"); /*else if (c instanceof ConceptList) { for (Concept c2 : ((ConceptList) c).list) buf.append(renderConcept(c2) + "\n"); }*/ else { buf.append(c.id + " " + shortDynamicClassName(c)); for (S field : listFields(c)) { O val = cget(c, field); if (val != null) { buf.append(" " + field + "="); buf.append(renderConceptShort(val)); } } } ret str(buf); } static S renderConceptShort(O val) { if (val instanceof Str) ret quote(((Str) val).name); else if (val instanceof AThing) ret "a " + renderConceptShort(((AThing) val).thing.get()); else if (val instanceof Concept) ret shortDynamicClassName(val) + ((Concept) val).id; else ret struct(val); } static S renderQuestion(Concept.Ref q) { ret renderQuestion(q.get()); } static S renderQuestion(Question q) { ret q.originalText + " (" + shortDynamicClassName(q) + ")"; } svoid printQuestionsAndAnswers { L open = list(OpenQuestion.class); if (nempty(open)) { printAsciiHeading("Open questions"); for (OpenQuestion oq : open) printIndent(renderQuestion(oq.question)); } L answered = list(AnsweredQuestion.class); if (nempty(answered)) { printAsciiHeading("Answered questions"); for (AnsweredQuestion aq : answered) { printIndent(2, renderQuestion(aq.question)); Concept a = aq.answer.get(); if (a instanceof ConceptList) for (Concept c2 : ((ConceptList) a).list) printIndent(4, renderConcept(c2)); else printIndent(4, renderConcept(a)); } } } static bool logic_parse(S s) { new Matches m; if "the plural of * is *" { assertEqic(m.unq(1), plural(m.unq(0))); assertEqic(m.unq(0), singular(m.unq(1))); true; } if "a * has *" { Concept main = aThing(m.unq(0)); Concept part = concept(singularFromPlural(m.unq(1))); uniqueConcept(HasMulti.class, "main", main, "part", part); true; } if "a * has a *" { Concept main = aThing(m.unq(0)); Concept part = concept(m.unq(1)); uniqueConcept(HasA.class, "main", main, "part", part); true; } if "the number of * in a * is *" { Concept main = aThing(m.unq(1)); Concept part = concept(singularFromPlural(m.unq(0))); int n = parseInt(m.unq(2)); uniqueConcept(MultiCount.class, "main", main, "part", part, "count", n); true; } if "let's assume * is a *" || "* is a *" { Concept thing = concept(m.unq(0)); Concept type = aThing(m.unq(1)); uniqueConcept(IsA.class, "thing", thing, "type", type); true; } if "how many * are in *" { Concept main = concept(m.unq(1)); Concept part = concept(singularFromPlural(m.unq(0))); uniqueConcept(OpenQuestion.class, "question", uniqueConcept(HowManyAreIn.class, "originalText", s, "main", main, "part", part)); true; } if "what does * have" { Concept thing = concept(m.unq(0)); newQ(uniqueConcept(WhatDoesXHave.class, "originalText", s, "thing", thing)); true; } if "does * have a *" { Concept x = concept(m.unq(0)); Concept y = concept(m.unq(1)); newQ(uniqueConcept(DoesXHaveAY.class, "originalText", s, "x", x, "y", y)); true; } if "* is a synonym of *" { mergeStrs(concept(m.unq(0)), concept(m.unq(1))); true; } if (trim(s).endsWith("?")) { uniqueConcept(OpenQuestion.class, "question", uniqueConcept(Question.class, "originalText", s)); true; } false; } static void newQ(Question q) { uniqueConcept(OpenQuestion.class, "question", q); } static void logic_processRules { // Infer statements. // x is a y && a y has n z => x has n z for (IsA isA : list(IsA.class)) { Concept x = isA.thing.get(), y = isA.type.get(); for (MultiCount mc : conceptsWhere(MultiCount.class, "main", y)) uniqueConcept(MultiCount.class, "main", x, "part", mc.part, "count", mc.count); // todo: automate the copying } // x is a y && a y has a z => x has a z for (IsA isA : list(IsA.class)) { Concept x = isA.thing.get(), y = isA.type.get(); for (HasA h : conceptsWhere(HasA.class, "main", y)) uniqueConcept(HasA.class, "main", x, "part", h.part); } // x has a y => x has "the y of x" for (HasA h : list(HasA.class)) if (h.main.get() instanceof DefiniteThing) uniqueConcept(Has.class, "main", h.main, "part", uniqueConcept(TheXOfY.class, "x", h.part, "y", h.main)); // Answer questions. for (OpenQuestion oq : list(OpenQuestion.class)) { Question _q = oq.question.get(); if (_q instanceof HowManyAreIn) { HowManyAreIn q = cast _q; MultiCount mc = conceptWhere(MultiCount.class, "main", q.main, "part", q.part); if (mc != null) answerQuestion(q, mc); } if (_q instanceof WhatDoesXHave) { WhatDoesXHave q = cast _q; new ConceptList l; l.addAll(conceptsWhere(HasA.class, "main", q.thing)); l.addAll(conceptsWhere(Has.class, "main", q.thing)); answerQuestion(q, l); } if (_q instanceof DoesXHaveAY) { DoesXHaveAY q = cast _q; if (hasConcept(HasA.class, "main", q.x, "part", q.y)) answerQuestion(q, true); } } } svoid logic_main { L sentences = sentencesFromHTML(input); print(numberLines(sentences)); for (S s : sentences) { if (!logic_parse(s)) print("? " + s); } processRulesMulti(); printConcepts(); printQuestionsAndAnswers(); if (countConcepts(OpenQuestion.class) == 0) print("\nAll questions answered!"); else print("\nOpen questions remaining."); }