Introducing the Self scripting language |
The Self scripting language is Bot Libre's language for scripting bot responses. Self is based on the syntax of JavaScript with several extensions for language processing. Self is an integrated environment that merges JavaScript, state machines, patterns, and an object database. If you already know JavaScript, you should find the Self syntax quite familiar. Self supports most JavaScript concepts and syntax, (if you notice something missing you would like, please let us know). If you are new to programming, the JavaScript syntax is quite simple, and there are lots of resources available on the Internet (such as w3schools). One big thing about Self is that it is integrated with the bot's knowledgebase. This makes it easy to access any of the bot's knowledge and add new knowledge. Self is a persistent language, any data your create or change will be persistent in the bot's knowledgebase. The Self code objects are also stored in the bot's knowledgebase, so a Self script can actually change itself, hence the name "Self". There are two ways that you can utilize Self. The simplest is to define a Template response. You can define a template response anywhere you define a response, including the Training & Chat Logs page, or in a chat correction. A template response is a response to a phrase or a pattern that can include Self code. For example "What is your name?" could have the template response Template("My name is {#self.name}."). The { } brackets are used to denote Self code embedded within the response text, and the Template keyword is required to define a template response. The code within the brackets is Self scripting code. The second usage of Self is from a program script. Program scripts can be defined or imported from the Scripts page in your bot's Admin Console. A new bot will have a default bootstrap set of scripts, that can do things such as understand simple language, perform math, tell the current date or time, or look information up on Freebase. You can alter, extend, import, or create your own scripts to do virtually anything. Scripts are more complex than templates, but more functional. A Self script is essentially a state machine that processes the input.
Self SyntaxThe Self syntax is the same for template responses and functions within a Self script. Self scripts also contain additional syntax for defining state machines. A state object is similar to a function in JavaScript but is specialized for processing input. Self also merges many concepts from AIML, such as Pattern and Template objects, and SRAI calls. Self is an untyped object oriented language the same as JavaScript. Everything in Self is an object (this includes the Self code itself). An object can be data, such as a string, number, date, time, or symbol. Objects can have relationships to other objects. Data TypesThe Self data types are similar to the JavaScript data types, and most other programming languages. Self also adds special symbol, pattern, and template data types. The following are examples of Self data types:
VariablesVariables in Self can be declared using the var operator the same as JavaScript. Also similar to JavaScript, variables do not need to be declared, but will be declared automatically when used. Within a template or state Self has access to several global variables:
OperatorsThe operators in Self are similar to JavaScript, and most other programming languages. Self also defines a few special operators for knowledge processing, or borrowed from AIML. The following are the Self operators:
ifThe if statement is the same as JavaScript and similar to other languages, in that it has a logical condition, and optional else if and else conditions. Examples: if (value == null) { ... } else { ... } if (value) { ... } if (!value) { ... } if ((word == "you") && (word2 == "are")) { ... } if ((word == "I") || (word == "me")) { ... } if (value != value2) { ... }
doThe do statement is similar to other languages. do is used to perform multiple operations sequentially. Examples: do { response = new (#sentence); response.append(#word, "Hello"); response.append(#word, "world"); return response; } forThe for statement is similar to JavaScript and other languages. for is used to iterate over an object's relationships. It takes the relationship type, the source object, and a variable to assign each related value to. Examples: for (word in sentence.word) { if (word.has(#instantiation, #keyword)) { conversation.topic = word; } } for (count in number.sequence) { response.append(#word, word); } returnThe return operator will return the result from the current function. If an function has no return value, the result of the last operation will be returned. If null is returned it is an indication that function failed to generate a response, and if used from a state machine, the next case or answer will be used. Examples: if (word == "hello") { return "hello there"; } notThe ! operator will negate a logical primitive (true -> false, false - > true). If the value is not a logical value, the value is returned. Examples: negative = !negative; assignThe = operator assigns a new value to a variable. Examples: name = Language.word(firstName, lastName); newThe new operator creates a new object of the type. An object can be an instantiation of one or more classification objects. Most classifications are defined by a symbol, you can define your own classifications, they are just another object that is an instantiation of #classification. You can also add a classification to an existing object using the instantiation relationship. Common classifications include, #word, #compound-word, #name, #sentence, #number, #date, #time, #person, #speaker, #classification, #formula, #pattern, #variable, #keyword, #thing, #description, #action, #adjective, #noun, #verb, #punctuation, #question, #paragraph, #topic, #tweet, #email, and #url.Examples: response = new Sentence(); response = new (#sentence, #question); name.instantiation = #name; SymbolThe Symbol operator create a new primitive symbol representing the meaning of a word. Symbols are unique, global, and persistent objects. Any relationship set on a symbol will be persisted and remembered. There are many common symbols used in the bot's knowledgebase, the symbol #self represents the bot. Examples: Language.define(word, Symbol(word)); getThe . operator gets the value of a relationship. If the relationship has multiple values, get will return the most conscious to the current context. most conscious means the relationship that has the highest correctness factor, and is most associated to the recent input. get can optionally include an [] modifier to get a specific index in an ordered relationship. Negative index values will return the indexed element from the end.Examples: age = speaker.age; sentence.word[2]; sentence.word[-1]; setThe = operator sets the value of a relationship. Set first clears any existing relationships of the same type, and is meant to be used with single value relationships.Examples: conversation.topic = star; speaker.age = 44; response.word[0] = "Hello"; addThe =+ operator adds a value to a relationship. add is similar to set, but adds to the relationship, and does not replace the existing value. If the value already exists, its correctness will be increased.Examples: thing[action] =+ description; sentence.response =+ response; speaker.gender =+ #male; removeThe =- operator removes a value from a relationship. The remove operator can be used to define an inverse relationship. An inverse relationship can be used to inform the bot that a such a relationship is incorrect. If dissociate is used on a inverse relationship that already exists, its correctness will be decreased.Examples: sentence.response =- response; speaker.gender =- #female; randomThe random operator selects one of the arguments at random.Examples: random ("Hello", "Hi", "Hey", "G'day mate"); sraiThe srai or redirect operator recursively evaluates the phrase and returns the response. It can be used to redirect a response, or break up a question into several components. srai was borrowed from AIML, and can be used in conjunction with patterns to process text fragments.Examples: srai ("hello"); sraixThe sraix or request operator sends the phrase to a remote service. A settings objects can define which service to use and provide a data hint or default. A service can be a web service such as #freebase, #wikidata, or #pannous, or another bot on another server.Examples: sraix (song, { service : #wikidata, hint : "performer")); Object Methods and ClassesSelf defines several object method available to all objects. Object methods:
String methods:
Self defines several utility classes and methods. Classes can be referenced by name similar to JavaScript i.e. Language.word("hello") or as symbols i.e. #language.word("hello"). Language methods:
Date methods:
Util methods:
Math methods:
Self ScriptsSelf is based on processing input. An input could be a chat message, or an email, tweet, or other input. The input is wrapped in an input object which contains the phrase or data. A Self script will normally begin by extracting the phrase from the input, then processing each word in the phrase in sequence. A Self script is broken into a series of states. The first state will process the first word, then if the word matches a case, it will transition to the child state to process the next word. When a state sequence reaches the end of the sequence of words in a phrase, it is considered a successful match. Once matched, if the state contains an answer, the answer will be evaluated, and the response returned. A Self script is composed of the following components:
StateThe state defines the current input processing. Every Self script start with a root state, which is the name of the script. The state can evaluate the current input and transition to another state, or return an answer. A state can include definitions of sub-states, variables, and functions. A state is composed of a sequence of operations which can include case, pattern, do, goto, and return. Examples: // Example simple pattern based state. state Hello { pattern "hi" template "Hi there"; pattern "^ hello ^" template "Hello there"; pattern "[bye goodbye]" template "Goodbye."; pattern "my name is *" template Template("Pleased to meet you {star}"); pattern "what is your name" template Template("My name is {#self.name}"); pattern "what (day) is today" template Template("Today is {Date.date()}"); } // Example state that parses a sentence and executes a function state Repeat { case input goto sentenceState for each #word of sentence; state sentenceState { case "repeat" goto repeatState; state repeatState { case someWord goto repeatWordState; state repeatWordState { case digits goto repeatWordNState; var digits { meaning : number; } var number { instantiation : #number; } state repeatWordNState { case "times" goto repeatWordNTimesState; state repeatWordNTimesState { answer repeatResponse(); function repeatResponse() { response = new (#sentence); for (count in number.sequence) { response.append(#word, someWord); } } } } } } } caseThe case operator defines a state transition. If the current input matches the case value or variable, then it will transition to the case goto state. A case can also return a template, return and abort the current state, or restrict the match to a topic or previous that match. A state can also process the transition state for a collection of values. Examples: case "hello" goto helloState case name goto nameState case "lol" template "Very funny." case "what" topic "joke" that "what do you get when you cross music and an automobile" template "a car-tune" case "huh" return patternThe pattern operator evaluates if the input sentence matches the pattern. A pattern is an easy way to evaluate a phrase and return a template response. A pattern can include wildcards using the * character. The * word or text fragment it matched to the star variable which can be used in the response. Examples: pattern "hello" template "Hi there"; pattern "my name is *" template Template("Pleased to meet you {star}"); pattern "what *" topic "joke" that "what do you get when you cross music and an automobile" template "a car-tune"; answerAn answer defines a state's response, and is evaluated if the state is done processing input. Examples: answer "Hi there" answer Template("Pleased to meet you {star}"); answer repeatResponse(); functionA function defines a Self function that can be evaluated to return a response, or process input. Examples: function todayResponse() { var response = new (#sentence); response.append(#word, "Today is"); response.append(#word, Date.date()); response.append(#word, "."); return response; } varA variable defines a matching pattern, or temporary state. Variables can define relationships that must be included or excluded to evaluate a match. Variables are used in a case operation, if the current input matches the variable, then the case is evaluated. Variable make it possible to define generic functions that can process any noun, number, or name. Examples: var digits { meaning : :number; } var number { instantiation : #number; } var name { instantiation : #name; } var noun { instantiation : #noun; } var firstName { instantiation : ! #verb, ! #adjective, ! #pronoun, ! #punctuation; : "Bob", "Fred", "John", "Jill"; : ! "long", ! "cool"; } Self vs AIMLSelf is very different than AIML. Self is based on knowledge and state processing, where as AIML is based on patterns and text processing. Self can do everything that AIML can do, and a lot more. If you are experienced with AIML, and want to know how to do the same thing in Self, just import the AIML script and it will be converted to Self.
Self ExamplesBot Libre provides a shared repository of Self scripts and examples that you can import, customize, and learn from. You bot will also come bootstrapped with several Self scripts that you can learn from and customize. See the Self script category for all of the example scripts. |
|
|
|
|