UNPKG

tpmkms

Version:

Reusable libraries for Entodicton, a natural language to json converter

419 lines (399 loc) 15.6 kB
const { knowledgeModule, ensureTestFile, where, unflatten, flattens } = require('./runtime').theprogrammablemind const { defaultContextCheck } = require('./helpers') const _ = require('lodash') const gdefaults = require('./gdefaults.js') ensureTestFile(module, 'meta', 'test') ensureTestFile(module, 'meta', 'instance') const meta_tests = require('./meta.test.json') const instance = require('./meta.instance.json') const { hashIndexesGet, hashIndexesSet, translationMapping, translationMappings } = require('./helpers/meta.js') const { zip, words } = require('./helpers.js') const template = { configs: [ // "if f then g", //"if e or f then g", ] }; // TODO -> if a car's top speed is over 200 mph then the car is fast const config = { name: 'meta', operators: [ "((phrase) [means] (phrase))", // if x likes y then x wants y "([if] ([ifAble]) ([then] ([ifAble])))", "(([orAble|]) [orList|or] ([orAble|]))", // "cats is the plural of cat" // "is cat the plural of cats" { pattern: "([x])", scope: "testing" }, // if f x then g x { pattern: "([e])", scope: "testing" }, { pattern: "([f])", scope: "testing" }, { pattern: "([g])", scope: "testing" }, { pattern: "([undefined])", scope: "testing" }, { pattern: "([defined])", scope: "testing" }, /* if creating a new word make a motivation to ask if word is plura or singlar of anohter wordA make object -> operator+bridge made add word add word -> check fo plural or singular if so make motivate to ask (if yes update all contepts dups) update hierarchy */ //"show the definition of word" // "([testWord2|])", // make end of sentence an operators -> so means sucks up all the words // undefine (word) // forget (word) // what does (word) mean ], associations: { positive: [ { "context": [['*', 0], ['means', 0], ['*', 0]], "choose": { index: 1, increment: true } }, { "context": [['*', 1], ['means', 0], ['*', 0]], "choose": { index: 1, increment: true } }, { "context": [['*', 1], ['means', 0], ['*', 1]], "choose": { index: 1, increment: true } }, ] }, priorities: [ { "context": [['orList', 0], ['if', 0], ['then', 0], ], "choose": [0] }, // [['means', 0], ['is', 0]], ], hierarchy: [ { child: 'e', parent: 'orAble', scope: "testing" }, { child: 'f', parent: 'orAble', scope: "testing" }, { child: 'g', parent: 'ifAble', scope: "testing" }, { child: 'orAble', parent: 'ifAble' }, ], bridges: [ /* { id: "synonym", // implicit words in singular/plural words: words('synonym'), operator: "([synonym])", }, { id: 'synonymOfWord', operator: "((synonym/*) [synonymOfWord|of] (word))", bridge: "{ ...next(operator), word: after[0] }", evaluator: ({context}) => { } }, */ {id: "orList", level: 0, selector: {left: [{ marker: 'orAble' }], right: [{ marker: 'orAble' }], passthrough: true}, bridge: "{ ...next(operator), value: append(before, after) }"}, {id: "orList", level: 1, selector: {left: [{ marker: 'orAble' }], passthrough: true}, bridge: "{ ...operator, value: append(before, operator.value) }"}, // {id: "orList", level: 0, selector: {/*match: "same", type: "infix",*/ left: [{ marker: 'orAble'}], right: [{ marker: 'orAble' }], passthrough: true}, bridge: "{ ...next(operator), value: append(before, after) }"}, // {id: "orList", level: 1, selector: {/*match: "same",*/ left: [{ marker: 'orAble' }], passthrough: true}, bridge: "{ ...operator, value: append(before, operator.value) }"}, { id: "means", level: 0, bridge: "{ ...next(operator), from: before[0], to: after[0] }" }, { id: "if", level: 0, bridge: "{ ...next(operator), antecedant: after[0], consequence: after[1].consequence }" }, { id: "then", level: 0, bridge: "{ ...next(operator), consequence: after[0] }" }, { id: "ifAble" }, { id: "orAble" }, { id: "x", scope: "testing" }, { id: "e", scope: "testing" }, { id: "f", scope: "testing" }, { id: "g", scope: "testing" }, { id: "undefined", scope: "testing" }, { id: "defined", scope: "testing" }, // { id: "testWord2", level: 0, bridge: "{ ...next(operator) }" }, ], version: '3', words: { "literals": { // 'testWord2': [{"id": "testWord2", "initial": "{ value: 'testWord2Value' }" }], // TODO make this development and select out for module // 'x': [{id: "x", initial: "{ value: 'x' }", scope: "testing" }], // 'f': [{id: "ifAble", initial: "{ word: 'f' }", scope: "testing" }], // 'g': [{id: "ifAble", initial: "{ word: 'g' }", scope: "testing" }], 'f': [{id: "f", initial: "{ value: 'f', word: 'f' }", scope: "testing" }], 'x': [{id: "x", initial: "{ value: 'x', word: 'x' }", scope: "testing" }], 'gq': [{id: "g", initial: "{ word: 'gq', query: true }", scope: "testing" }], } }, generators: [ { where: where(), match: ({context}) => context.marker == 'undefined', apply: ({context}) => 'undefined', scope: "testing", }, { where: where(), match: ({context}) => context.marker == 'defined', apply: ({context}) => 'defined', scope: "testing", }, { where: where(), match: ({context}) => context.evalue && !context.paraphrase, apply: ({context}) => context.evalue.verbatim, scope: "testing", }, { where: where(), match: ({context}) => context.marker == 'orList' && context.paraphrase, apply: async ({context, gs}) => { return await gs(context.value, ', ', ' or ') }, priority: -1, }, { priority: -1, where: where(), match: ({context}) => context.marker == 'means' && context.paraphrase, apply: async ({context, g}) => { return `${await g({ ...context.from, paraphrase: true})} means ${await g(context.to)}` } }, { where: where(), match: ({context}) => context.marker === 'ifAble', apply: ({context}) => context.value, scope: "testing", }, { where: where(), match: ({context}) => ['x', 'g', 'f', 'e', 'ifAble'].includes(context.marker), apply: ({context}) => `${context.word}`, scope: "testing", }, { where: where(), match: ({context}) => context.marker === 'if', apply: async ({context, g}) => { return `if ${await g(context.antecedant)} then ${await g(context.consequence)}` }, priority: -1, }, ], semantics: [ { where: where(), match: ({context}) => ['e', 'f', 'g'].includes(context.marker), apply: ({context}) => { context.evalue = { verbatim: `this is ${context.marker} response` } context.isResponse = true }, scope: "testing", }, { where: where(), match: ({context}) => context.marker == 'orList', apply: async ({context, s}) => { const response = [] for (const value of context.value) { response.push(await s(value)) } context.evalue = { marker: 'orList', value: response } context.isResponse = true }, }, { where: where(), match: ({context}) => context.marker == 'if', apply: ({config, context}) => { // setup the read semantic // !topLevel or maybe !value??!?! function match(defContext) { return ({context}) => context.marker == (defContext.consequence || {}).marker && context.query // && !context.value } function apply(DEFINITIONs, DERIVED) { const mappingss = translationMappings(DEFINITIONs, DERIVED) function invertMappings(mappings) { return mappings.map( ({ from, to }) => { return { to: from, from: to } } ) } return async ({context, s, config}) => { DEFINITIONs = _.cloneDeep(DEFINITIONs) //const mappings = mappingss[0] let toPrimes = [] for (const [TO, mappings] of zip(DEFINITIONs, mappingss)) { for (const { from, to } of invertMappings(mappings)) { hashIndexesSet(TO, to, hashIndexesGet(context, from)) } // next move add debug arg to s and g TO.query = true toPrimes.push([await s(TO), mappings]) } let hasResponse = false let hasValue = false for (const [tp, _] of toPrimes) { if (tp.evalue) { hasResponse = true if (tp.evalue.value) { hasValue = true } } } // maps the response back let response; if (hasResponse) { if (hasValue) { const valuesPrime = [] toPrimes = toPrimes.filter( (toPrime) => (toPrime[0].evalue || {}).truthValue ) for (const [relations, mappings] of toPrimes) { for (const relation of relations.evalue.value) { valuePrime = _.cloneDeep(DERIVED) for (const { from, to } of mappings) { hashIndexesSet(valuePrime, to, hashIndexesGet(relation, from)) } valuePrime.paraphrase = true valuesPrime.push(valuePrime) } } response = { marker: 'list', listable: true, truthValue: valuesPrime.length > 0, value: unflatten(valuesPrime, context.flatten || []) } } else { const toPrime = toPrimes[0][0] response = toPrime.evalue } } else { const toPrime = toPrimes[0][0] response = toPrime } context.evalue = response context.isResponse = true } } let antecedants = [_.cloneDeep(context.antecedant)] if (context.antecedant.marker == 'orList') { antecedants = antecedants[0].value } const semantic = { notes: "setup the read semantic (1)", // match: match(context), where: where(), match: match(context), apply: apply(antecedants, _.cloneDeep(context.consequence)), } config.addSemantic(semantic) } }, { notes: 'from means to where from is unknown', where: where(), match: ({context}) => context.marker == 'means' && context.from.marker == 'unknown', apply: async ({config, context, kms, e, isTest}) => { if (kms.dialogues) { if (context.from.unknown && !context.to.unknown) { // kms.dialogues.api.makeObject({ context: context.from, types: [context.to.marker], source_value: context.to.value, config }); await kms.dialogues.api.makeObject({ context: context.from, types: [context.to.marker], source_value: context.to.value, config }); } if (context.to.value) { kms.stm.api.setVariable(context.from.value, context.to.value) // config.addWord(context.from.word, context.to) } else { await kms.dialogues.api.makeObject({ context: context.from, types: context.to.types || [], config }); kms.stm.api.setVariable(context.from.value, context.to) } } } }, { notes: 'x means y where x and y have known markers', where: where(), match: ({context}) => context.marker == 'means', apply: async ({config, context, g}) => { // setup the write semantic { function matchByMarker(defContext) { return ({context}) => context.marker == defContext.from.marker && !context.query && !context.objects } function matchByValue(defContext) { return ({context}) => context.evalue == defContext.from.value && !context.query && !context.objects } function apply(mappings, TO) { return async ({context, s}) => { TO = _.cloneDeep(TO) for (const { from, to } of mappings) { hashIndexesSet(TO, to, hashIndexesGet(context, from)) } toPrime = await s(TO) context.result = toPrime.result } } const mappings = translationMapping(context.from, context.to) let match = matchByMarker(context) if (context.from.evalue) { match = matchByValue(context) } const semantic = { notes: "setup the read semantic (2)", // match: match(context), where: where(), match: match, apply: apply(mappings, _.cloneDeep(context.to)), } config.addSemantic(semantic) } // setup the read semantic { function matchByMarker(defContext) { return ({context, uuid}) => context.marker == defContext.from.marker && (context.query || context.evaluate) && !context[`disable${uuid}`] } function matchByValue(defContext) { return ({context, uuid}) => context.value == defContext.from.value && (context.query || context.evaluate) && !context[`disable${uuid}`] } function apply(mappings, TO) { return async ({uuid, context, s, g, config}) => { TO = _.cloneDeep(TO) for (const { from, to } of mappings) { hashIndexesSet(TO, to, hashIndexesGet(context, from)) } // next move add debug arg to s and g // TODO why is there query and evaluate? if (context.query) { TO.query = context.query } else { TO.evaluate = context.evaluate } TO[`disable${uuid}`] = true toPrime = await s(TO) if (context.query) { if (toPrime.evalue) { context.evalue = toPrime.evalue } else { context.evalue = toPrime } } else { context.evalue = toPrime.evalue } } } const mappings = translationMapping(context.from, context.to) let match = matchByMarker(context) context.metaInfo = `The mapping from from the expression being defined "${await g({...context.from, paraphrase: true})}" to the definition phrase "${await g({...context.to, paraphrase: true})}" is ${JSON.stringify(mappings)}` if (context.from.value) { match = matchByValue(context) } const semantic = { notes: "setup the read semantic", // match: match(context), where: where(), match: match, apply: apply(mappings, _.cloneDeep(context.to)) , } config.addSemantic(semantic) } } } ], }; knowledgeModule({ config, includes: [gdefaults], module, description: 'Ways of defining new language elements', test: { name: './meta.test.json', contents: meta_tests, include: { words: true, }, checks: { context: [defaultContextCheck()], }, }, instance, template, })