1
\$\begingroup\$

I am trying to make a chatbot using javascript by deconstructing a sentence into its intent by separating the Noun's Verb's, Adjectives, Durations's, Numbers etc... to construct a data query to try to answer the user's question.

I have built the parser and believe I have a good handle on that, but I would like to employ polymorphism in my callback function so I can use common patterns in the sentence structure to execute different functions.

I initially thought to use an object that had keys set by joining an array of the types names

{'TypeA,TypeB,TypeC': fn }

This would be the fastest to find the callback function, but then I cannot use inheritance to determine if the given argument is an instance or a descendent of the type in the function signature.

My Idea was to use the native Map object to store arrays that contain references to the constructors of the types I am expecting, then before executing the callback checking the given arguments types with the stored functions, using inheritance

// set a callback to be called if arguments are of TypeA and TypeB
polymorphic.set(
  [TypeA, TypeB],
  function first(arg1, arg2) {
    // do something
  }
)

// set a callback to be called if arguments are of TypeA and TypeC
polymorphic.set(
  [TypeA, TypeC],
  function second(arg1, arg2) {
    // do something
  }
)
// running this would call the second polymorphic function as the 
// types match
parse(TypeA('string'), TypeC('string'))

This seems like it's going to introduce unwanted complexity, so I'm looking for a better way if anyone has any suggestions.

Here is a quick working prototype that shows the logic in determing the correct function signature based on the arguments provided to the parse function.

const data = {
  javascript: 10,
  php: 8,
  html: 6
}

function Intent() {}

function Noun(val) {
  if (this instanceof Noun === false)
    return new Noun(val)
  this.desc = val
  this.val = data[val]
}

Noun.prototype = new Intent

function Adjective(val) {
  if (this instanceof Adjective === false)
    return new Adjective(val)
  this.val = val
}

Adjective.prototype = new Intent

Adjective.prototype.exec = function(...args) {
  return this[this.val](...args)
}

Adjective.prototype.better = function(left, right) {
  this.opposite = 'worse'
  return left.val > right.val
}

const polymorphic = new Map

// add a new function definition
polymorphic.set(
  [Noun, Adjective, Noun],
  function compare(left, operator, right) {
    if (operator.exec(left, right)) {
      return `${left.desc} is ${operator.val} than ${right.desc}`
    }
    return `${left.desc} is ${operator.opposite} than ${right.desc}`
  }
)

// check if the left and right array of types are the same
function sameTypes(types, args) {
  if (types.length !== args.length) {
    return false
  }
  // iterate through the types and args to check that
  // they are related
  for (let ii = 0, ll = types.length; ii < ll; ii++) {
    if (args[ii] instanceof types[ii] === false) {
      return false
    }
  }
  return true
}

function parse(...instructions) {
  // iterate through all the polymorphic types
  for ([types, fn] of polymorphic) {
    // check if we have a match
    if (sameTypes(types, instructions)) {
      // run the callbackk function with the arguments
      console.log(fn(...instructions))
    }
  }
}

parse(Noun('javascript'), Adjective('better'), Noun('php'))
parse(Noun('html'), Adjective('better'), Noun('php'))

\$\endgroup\$
  • 1
    \$\begingroup\$ I'm pretty sure you can't use a naive parser to do NLP... If you're not doing NLP, (read: if you can actually do this with a parser) then you'll have some kind of grammar. Would you mind including the "syntax" for the things you want to parse? \$\endgroup\$ – Vogel612 Dec 8 '16 at 11:04
  • \$\begingroup\$ @Vogel612 I don't want to do anything quite that involved. I only want to take basic questions and convert them into data queries. This isn't a research project, but messing around and want a question and answer for a portfolio. Here is a codepen I made while messing around with the idea. codepen.io/synthet1c/pen/MbVLXp \$\endgroup\$ – synthet1c Dec 8 '16 at 11:13
  • \$\begingroup\$ Check out npmjs.com/package/aimlinterpreter , and build your solution on top of that. Less effort,far better for your portfolio. \$\endgroup\$ – konijn Dec 8 '16 at 12:43
  • \$\begingroup\$ @konijn thanks for recommending aiml, I will certainly have a look at that, however, this question is regarding polymorphism and trying to get a reasonable efficiency with maximum flexibility. \$\endgroup\$ – synthet1c Dec 9 '16 at 1:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.