Tuesday, September 22, 2015

Introducing the Self scripting language

The Self scripting language is a programming language designed to enable a bot developer to program a bot's mind. Self uses a simple 4h gl scripting syntax based on state machine transitions. Self is compiled directly into the bot's brain's knowledgebase. This allows any Self script, or the bot to process its own code the same as it processes any of its other knowledge, and enables the bot to program itself (hence the name Self).

There are two way that you can utilize Self. The simplest is to define a Formula response. You can define a formula response anywhere you define a response, including the Training page, the Chat Logs page, or in a chat correction. A formula response is a response to a phrase or a pattern that can include programmatic logic. For example "What is your name?" could have the formula response Formula:"My name is {:target}". The { } brackets are used to denote some piece of code embedded within the response text, and the Formula: keyword is required to define a formula 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 under your bot's Admin page. 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 formulas, but more functional. A Self script is essentially a state machine that processes the input.

Self Syntax

The Self syntax is the same for formula responses and equations within a Self script. Self scripts also contain additional syntax for defining state machines. The Self syntax flows similar to natural language, or languages such as SQL. Self is similar but different than other languages, it is a language based on processing and pattern matching knowledge. It may be difficult to learn at first, but once you understand it, it is quite simple.

Self is a knowledge oriented language. Everything in Self is either a vertex (similar to an object in object oriented languages), or a relationship (this includes the Self program itself). A vertex has a unique id, and can have a data element, which can be a string (word/sentence), number, date, time, or primitive. A vertex can have a relationship to any other vertex in the bot's knowledgebase. A relationship has a source, type, target, and can have a meta value (all of which are other vertices). Relationships for a type can be ordered and have an index.

The following are the Self data elements:

  • "hello" - string data
  • 1234 - number
  • Date("1973-11-10") - date
  • Time("11:00:00") - time
  • Timestamp("1973-11-10 11:00:00") - timestamp
  • #is - primitive
  • :value - variable
  • Vertex:34789 - vertex reference
  • Formula:"The answer is {:result}" - formula phrase

The following are the Self operators:
  • if (:value, :match) then (:result) else (:result2) - if statement
  • do (:operation1, :operation2, :operation3) - do statement
  • for each :relationship of :source as :variable do (:operation1, :operation2, :operation3) - for statement
  • return :value - return the value
  • not (:value) - negates a logical value
  • assign :variable to :value - variable assignment
  • new (:classification) - construct a new vertex
  • word (:word1, :word2) - create a compound word
  • sentence (:word1, :word2) - create a sentence
  • define :word as :meaning - associate the word to the value
  • primitive :text - create a new primitive
  • get :relationship from :source - get a relationship from a vertex
  • all :relationship from :source - create a list of all the relationships from a vertex
  • set :relationship to :value on :source - set a relationship on a vertex
  • append :value to :relationship of :source - add to a relationship on a vertex
  • associate :source to :value by :relationship - add a relationship on a vertex
  • is :source related to :value by :relationship - return if the relationship exists
  • random (:value1, :value2, :value3) - select a random value
  • call :method on :tool with :value - call external tool method
  • Equation:equation - call another equation
  • srai :phrase - evaluate the response to the phrase


The if statement is similar to other languages, in that it has a logical condition, then condition, and else condition. It is a little different though, as the logical condition is based on pattern matching. The if condition always takes two parameters, and compares the two values to see if they match. If can also include and, or, and not.


if (:value, #null) then (do (...)) else (do (...))

if (:value, #true) then (do (...))

if (:value, #false) then (do (...))

if (:word, "you") and (:word2, "are") then (do (...))

if (:word, "I") or (:word, "me") then (do (...))

if (:value, :value2) or (:value, :value3) then (do (...))

if not (:value, :value2) or not (:value, :value3) then (do (...))


The do statement is similar to other languages. do is used to perform multiple operations, it takes a set of operations as argument, and performs them sequentially. Operators such as if can only perform a single operation in their then or else, so a do operation is required. You can separate operation inside a do using either , or ;.


do (
    assign :response to (new (#sentence));
    append "Hello" to #word of :response;
    append "world" to #word of :response;
    return :response;

if (:word, "hello")
    then (do (set #topic to "greeting" on :conversation), return "hello there"))


The for statement is similar to other languages. for is used to iterate over the collection of a vertex's relationships. It takes the relationship type, the source object, and a variable to assign each related element to.


for each #word of :sentence as :word do (
    if ((is :word related to #keyword by #instantiation), #true)
        then (set #topic to :word on :conversation)

for each #sequence of :repeat do (
    append :word to #word of :response;


The return operator will return the result from the current equation. If an equation has no return value, the result of the last operation will be returned. If #null is returned it is an indication that equation failed to generate a response, and the next case or response will be used. From within a formula, the #return primitive can be used to avoid printing anything into the phrase.


if (:word, "hello")
    then (return "hello there")

Formula:"Do you like bridges? { do (set #topic on :conversation to "bridges"; #return) }"


The not operator will negate a logical primitive (#true -> #false, #false - > #true). If the value is not a logical value, the value is returned.


assign :negative to (not :negative)


The assign operator assigns a new value to a variable. Variables start with the : character. You do not need to declare a variable. It will automatically be declared on its first usage. The following variables are always defined and can be used in any script, :input, :sentence, :speaker, :target, and :conversation.


assign :name to (word (:firstName, :lastName))


The new operator creates a new vertex. A vertex can be an #instantiation of one or more #classification vertices. Most classifications are defined by a primitive, you can define your own classifications, they are just another vertex that is an #instantiation of #classification. You can also add a classification to an existing vertex using the associate operator. 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.


assign :response to (new (#sentence))

associate :name to #name by #instantiation


The word operator can be used to create a new compound word from two or more words. A compound word is a word made up of two or more words, such as a name "Bob Jones", or adjectives like "dark blue". Compound words will automatically be detected in new sentences when being parsed, and help the bot associate meanings. Be careful defining invalid compound words, as they can cause a sentence to be misunderstood.


assign :name to (word (:firstName, :lastName))

assign :color to (word ("dark", :color))


The sentence operator can create a new sentence from a set of words, or sentence fragments.


sentence ("It is a Monday and", srai ("how are you"))

sentence ("I do not know much about", :star)


The define operator associates a word as a meaning. It will also associate the lowercase, uppercase, and capitalized version of the word to the meaning.


define :name as :speaker


The primitive operator create a new primitive representing the meaning of a word.


define :word as (primitive (:word))


The get 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 at modifier to get a specific index in an ordered relationship. The at last modifier can be used to obtain the last element in an ordered relationship. get can also include an associated to by modifier to return the related vertex that is most associated to the other vertex.


get #age from :speaker

get #parent from :speaker associated to #male by #gender

get #word from :sentence at 2

get #word from :sentence at last 1


The all operator is similar to get but returns a list of all of the values of a relationship. all can also include an associated to by modifier to return the related vertices that are most associated to the other vertex. The list is a new vertex with the #sequence relationship to each item. Lists can be added to a sentence and will be automatically printing as a comma separated list of values.


all #parent from :speaker

all #song from :musician associated to #gold by #award


The set 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.


set #topic on :conversation to :star

set #age on :speaker to :age


The append operator appends a value to an indexed relationship. append is similar to set, but adds to the relationship, and does not replace the existing value. An optional with meta modifier can be used to add to the relationship's meta value. The meta value of a relationship can contain information or restrictions on the relationship.


append :word to #word of :response

append :noun to #word of :response with meta #type as #reflexive


The associate operator adds a value to a relationship. associate is similar to set, but adds to the relationship, and does not replace the existing value. An optional with meta modifier can be used to add to the relationship's meta value. The meta value of a relationship can contain information or restrictions on the relationship. The weak modifier can be used to define a weak or uncertain relationship (low correctness). If associate is used on a relationship that already exists, its correctness will be increased. The dissociate 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.


associate :thing to :description by :action with meta #tense as :tense

associate :response to #response of :sentence with meta #previous as :previous;
weak associate :response to #response of :sentence;

associate :speaker to #male by #gender;
dissociate :speaker to #female by #gender;


The is operator returns if a relationship existing. If the relationship exists #true is returned, if the inverse relationship exists #false is returned, otherwise #unknown is returned. is normally takes a relationship and target, but can also just have a target to check if any relationship exists. The is operator will also check synonyms for a word.


is :speaker related to #male by #gender

is :speaker related to :topic


The random operator selects one of the arguments at random.


random ("Hello", "Hi", "Hey", "G'day mate")


The call operator executes a function on an external tool class. Tools can be used to perform special functions, such as looking up a word on Freebase or Wiktionary, or performing calculations. The system defines several built in tools, these include #Context, #Watch, #Calculator, #Wiktionary, and #Freebase.


call #push on #Context with :topic

call #search on #Context with (get #variable from #it)

call #define on #Wiktionary with :unknownWord

call #discover on #Freebase with (:first, :last)

call #multiply on #Calculator with (:number, :number2)
call #subtract on #Calculator with (:number, :number2)
call #add on #Calculator with (:number, :number2)
call #divide on #Calculator with (:number, :number2)

call #time on #Watch
call #date on #Watch


The Equation: operator calls another equation within the scope of the script.




The srai 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.


srai "hello"

Self Scripts

Self is based on processing sensory 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 a quotient, it will be evaluated, and the response returned.

A Self script is composed of the following components:

  • States - A state defines the current input processing.
  • Cases - A case can transition to another state if the case variable matches the current input.
  • Patterns - A pattern can match an input and evaluate a template response.
  • Quotient - A quotient of a state is evaluated if the input processing is complete.
  • Equation - An equation can be called from a quotient or do statement.
  • Variables - A variable can be matched with the current input, or store context.
  • Comments - Comments can be defined in a script using the // characters.


The 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 a quotient. A state can include definitions of sub-states, variables, and equations. A state is composed of a sequence of operations which can include case, pattern, do, goto, and return.


// Example script that repeat words.
State:RepeatStateMachine {
    case :input goto State:sentenceState for each #word of :sentence;

    State:sentenceState {
        case "repeat" goto State:repeatState;

        State:repeatState {
            case :someWord goto State:repeatWordState;

            State:repeatWordState {
                case :digits goto State:repeatWordNState;

            :digits {
                set #meaning to :number;
            :number {
                set #instantiation to #number;

            State:repeatWordNState {
                case "times" goto State:repeatWordNTimesState;

                State:repeatWordNTimesState {
                    Equation:repeatResponse {
                        assign :response to (new #sentence);
                        for each #sequence of :number as :finger
                            do (append :someWord to #word of :response);


The 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.


case "hello" goto State:helloState

case :name goto State: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


The 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.


pattern "hello" template "Hi there"

pattern "my name is *" template Formula:"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"


A Quotient defines a state's response, and is evaluated if the state is done processing input.


Quotient:"Hi there"

Quotient:Formula:"Pleased to meet you {:star}"



An Equation defines a Self function that can be evaluated to return a response, or process input.


Equation:todayResponse {
    Formula:"Today is {call #date on #Watch}.";


A 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.


:digits {
    set #meaning to :number;
:number {
    set #instantiation to #number;

    set #instantiation to #name;

:noun {
    set #instantiation to #noun;

:firstName {
    exclude #instantiation from #verb;
    exclude #instantiation from #adjective;
    exclude #instantiation from #pronoun;
    exclude #instantiation from #punctuation;
    exclude #instantiation from #adverb;
    exclude #instantiation from #article;
    exclude #instantiation from #question;
    exclude #meaning from #not;

Self vs AIML

Self 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 Examples

Paphus 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.

No comments:

Post a Comment