Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / NLP

Natural Language Programming in the Ring Programming Language

5.00/5 (14 votes)
12 Oct 2016CPOL5 min read 27.4K   154  
Defining Natural Languages in the Ring programming language based on Object-Oriented Programming

Introduction

In 2010, I developed a new programming language called Supernova. This language uses a code that looks similar to Natural Language statements to create simple GUI applications. After five years, in the Ring programming language, we can get similar results, but now we have the ability to create/use code similar to Natural language statements in any domain that we like or need.

The Ring programming language comes with the Supernova sprite, but with more generalization and with a mix of other languages sprites.

The language comes with better support for Natural Language Programming and Declarative Programming. The innovation comes in supporting these paradigms with new practical techniques on the top of Object-Oriented Programming and Functional Programming. Ring provides programmers with the tools required to build a Natural Language like Supernova or Declarative Language like REBOL and QML without the need to know anything about (Compilers and Parsing). You get the language constructs ready for use to create domain-specific languages in a fraction of time.

Using the Ring programming language, we can create Natural programming languages based on classes and objects.

In Supernova language, we can type (I want window and the window title is hello world.) and it will create a GUI window with “Hello, World!” as the window title. When I created Supernova language in 2010, I discovered that using the Natural Code can be like English without limits and we can get the human language power in programming, but to implement that, we need a new language that is:

  1. General Purpose
  2. Practical
  3. Can create Natural Languages very quickly

So we can get a System that can increase ease of use and productivity to the maximum level.

Supernova was just a test for the idea. To get a near view about what are the advantages and disadvantages. After testing the new ideas, you provide something practical. So we have the Ring language after the Supernova language.

Why the Ability to Define Your Own Languages Instead of Just Handing Over the Syntax So You Can Parse It Using Whatever Code You Like?

It’s innovation - You create natural statements without the need to learn about parsing. You just use Classes which is an intelligent decision (where later we can mix between classes to support more statements based on the context - we can change and translate the defined statements and many more!). Also, the statements are added in Ring World where you can use any Ring statement.

Why Natural Language Programming, We Can Do Anything Using Imperative, Object-Oriented and Functional Languages?

When you design a new language, you can learn from the past but you must look forward and live in the Future. What you know about Natural Programming maybe based on the Old Knowledge about the power of these paradigms in the practical world and I agree with you but I see another technique that can be applied to get this to work practically. What you miss about Natural Languages is that they are Context Sensitive and this means we can use it and think different about how we can express our ideas.

Example (1): I want a window that contains 3 buttons.

In one sentence, I created 4 objects (the window and the three buttons) and added the buttons to the window. The idea of Natural Programming is to get many things done like that.

Example (2): Accept 2 numbers, then print the sum.

Background

You can check this article about the Supernova programming language and this article about the Ring programming language.

Also check the next Tutorials about the Ring programming language.

  1. Getting Started
  2. Control Structures
  3. Functions
  4. Lists
  5. Classes

Features in Ring Language That Help in Supporting Natural Language

(1) Compact Syntax, No explicit end for statements (No ; or ENTER is required)

Example:

See "What is your name? " give cName see "Hello " + cName

Or in another style:

Put "What is your name? " Get cName Put "Hello " + cName

(2) Using braces { }, we can access objects and use the attributes/methods directly as variables/functions:

Example:

New point                       # create new object using the point class
{                               # access the new object attributes and methods
        x = 10                  # set the x attribute to 10
        y = 20                  # set the y attribute to 20
        z = 30                  # set the z attribute to 30
        print()                 # call the print method
}                               # end of object access

Class Point                     # define the Point class
        x y z                   # the class contains three attributes x, y & z
        func print              # define the print method
                see x + nl +    # print the x attribute
                    y + nl +    # print the y attribute
                    z + nl      # print the z attribute

(3) We can define methods to be used when we set and get object attributes.

Example:

o1 = new person

o1.name = "Mahmoud"  see o1.name + nl

o1 { name = "Ahmed"  see name }

Class Person

        name family = "Fayed"

        func setname value
                see "Message from SetName() Function!" + nl
                name = value + " " + family

        func getname
                see "Message from GetName() Function!" + nl
                return "Mr. " + name

Output:

Message from SetName() Function!
Message from GetName() Function!
Mr. Mahmoud Fayed
Message from SetName() Function!
Message from GetName() Function!
Mr. Ahmed Fayed

Using the code

The next example presents how to create a class that defines two instructions:

  • The first instruction is: I want window
  • The second instruction is: Window title = <expr>

Also keywords that can be ignored like the ‘the’ keyword

New App
{
    I want window
    The window title = "hello world"
}

Class App

    # Attributes for the instruction I want window
        i want window
        nIwantwindow = 0
    # Attributes for the instruction Window title
    # Here we don't define the window attribute again
        title
        nWindowTitle = 0
    # Keywords to ignore, just give them any value
        the=0

    func geti
        if nIwantwindow = 0
            nIwantwindow++
        ok

    func getwant
        if nIwantwindow = 1
            nIwantwindow++
        ok

    func getwindow
        if nIwantwindow = 2
            nIwantwindow= 0
            see "Instruction : I want window" + nl
        ok
        if nWindowTitle = 0
            nWindowTitle++
        ok

    func settitle cValue
        if nWindowTitle = 1
            nWindowTitle=0
            see "Instruction : Window Title = " + cValue + nl
        ok

Output:

Instruction : I want window
Instruction : Window Title = hello world

What if we want to connect between the two instructions using ‘and’:

We have a problem because in Ring ‘and’ is a keyword.

We can change that using the ChangeRingKeyword command.

The ChangeRingKeyword command is executed in the scanner stage by the compiler (before parsing).

Note: Remember to restore the keyword again.

Syntax:

ChangeRingKeyword  <oldkeyword>  <newkeyword>

Example:

ChangeRingKeyword       and  _and

New App
{
                I want window and the window title = "hello world"
}

Class App

                # Attributes for the instruction I want window
                                i want window
                                nIwantwindow = 0
                # Attributes for the instruction Window title
                # Here we don't define the window attribute again
                                title
                                nWindowTitle = 0
                # Keywords to ignore, just give them any value
                                the=0  and=0

ChangeRingKeyword       _and  and

                func geti
                        if nIwantwindow = 0
                                nIwantwindow++
                        ok

                func getwant
                        if nIwantwindow = 1
                                nIwantwindow++
                        ok

                func getwindow
                        if nIwantwindow = 2
                                nIwantwindow= 0
                                see "Instruction : I want window" + nl
                        ok
                        if nWindowTitle = 0
                                nWindowTitle++
                        ok

                func settitle cValue
                        if nWindowTitle = 1
                                nWindowTitle=0
                                see "Instruction : Window Title = " + cValue + nl
                        ok

                func getand
                        see "Using : and" + nl

Output:

Instruction : I want window
Using : and
Instruction : Window Title = hello world

What if we want to define a new behavior for any operator like the “=” operator.

We can do this change using the ChangeRingOperator command to hide operator (change its name).

Then we can use the operator as identifier that we can handle its behaviour.

Syntax:

ChangeRingOperator  <oldoperator>  <newoperator>

Now we will change the ‘=’ operator to ‘is’.

Example:

ChangeRingKeyword       and  _and
ChangeRingOperator      =    is

New App
{
                I want window and the window title is "hello world"
}

ChangeRingOperator      is    =

Class App

                # Attributes for the instruction I want window
                                i want window
                                nIwantwindow = 0
                # Attributes for the instruction Window title
                # Here we don't define the window attribute again
                                title
                                nWindowTitle = 0
                # Keywords to ignore, just give them any value
                                the=0  and=0

ChangeRingKeyword       _and  and

                func geti
                        if nIwantwindow = 0
                                nIwantwindow++
                        ok

                func getwant
                        if nIwantwindow = 1
                                nIwantwindow++
                        ok

                func getwindow
                        if nIwantwindow = 2
                                nIwantwindow= 0
                                see "Instruction : I want window" + nl
                        ok
                        if nWindowTitle = 0
                                nWindowTitle++
                        ok

                func settitle cValue
                        if nWindowTitle = 1
                                nWindowTitle=0
                                see "Instruction : Window Title = " + cValue + nl
                        ok

Eval() Function

We can execute code during runtime from string using the Eval() function.

Syntax:

Eval(cCode)

Example:

Eval("nOutput = 5+2*5 " )
See "5+2*5 = " + nOutput + nl
Eval("for x = 1 to 10 see x + nl next")
Eval("func test see 'message from test!' ")
test()

Output:

5+2*5 = 15
1
2
3
4
5
6
7
8
9
10
message from test!

Using Eval() with our Natural Code:

func Main

  cProgram = ' I want window and the window title is "hello world" '

  MyLanguage(cProgram)

Func MyLanguage cCode

  # We add to the code the instructions that change keywords and operators
  # Because Eval() uses a new Compiler Object (the original keywords and operatos).

  cCode = '
        ChangeRingKeyword  and  _and
        ChangeRingOperator  =    is
  ' + cCode

  New App
  {
          eval(cCode)
  }

  Class App

          # Attributes for the instruction I want window
                  i want window
                  nIwantwindow = 0
          # Attributes for the instruction Window title
          # Here we don't define the window attribute again
                  title
                  nWindowTitle = 0
          # Keywords to ignore, just give them any value
                  the=0

          ChangeRingKeyword  and  _and
                  and=0
          ChangeRingKeyword  _and  and

          func geti
                if nIwantwindow = 0
                  nIwantwindow++
                ok

          func getwant
                if nIwantwindow = 1
                  nIwantwindow++
                ok

          func getwindow
                if nIwantwindow = 2
                  nIwantwindow= 0
                  see "Instruction : I want window" + nl
                ok
                if nWindowTitle = 0
                  nWindowTitle++
                ok

          func settitle cValue
                if nWindowTitle = 1
                  nWindowTitle=0
                  see "Instruction : Window Title = " + cValue + nl
                ok

BraceStart() and BraceEnd()

We can write code that will be executed before/after using { }:

Example:

o1 = new test {
        see "Hello" + nl
}

o1 {}

class test

        func bracestart
                see "start" + nl

        func braceend
                see "end" + nl

Output:

start
Hello
end
start
end

Using BraceExprEval()

The next example demonstrates how to use the “BraceExprEval” method to get expressions in Natural code.

Example:

new natural {
        create 5
}

class natural
        create=0
        lkeyword = false
        func braceexpreval r
                if lkeyword lkeyword=false return ok
                see "expr eval" + nl
                see "type: " + type(r) see nl
                see "value : " see r see nl
        func getcreate
                lkeyword = true
                see "create" + nl

Output:

create
expr eval
type: NUMBER
value : 5

Real Natural Code

The next example is a more advanced example.

# Natural Code
new program {
        Accept 2 numbers then print the sum
}

# Natural Code Implementation
class program
        # Keywords
                Accept=0 numbers=0 then=0 print=0 the=0 sum=0

        # Execution
        func braceexpreval x
                value = x
        func getnumbers
                for x=1 to value
                        see "Enter Number ("+x+") :" give nNumber
                        aNumbers + nNumber
                next
        func getsum
                nSUm = 0
                for x in aNumbers nSum+= x next
                see "The Sum : " + nSum
        private
                value=0 aNumbers=[]

Output:

Enter Number (1) :3
Enter Number (2) :4
The Sum : 7

Using BraceError()

The next examples demonstrates how to use the “BraceError” method to handle errors when accessing the object using braces {}.

Example:

func main
        o1 = new point {
                x=10 y=20 z=30
                TEST
                SEE test
        }

class point x y z
        func braceerror
                see "Handle Error!" + nl
                SEE "Message :" + cCatchError + nl
                if ( left(cCatchError,11) = "Error (R24)" ) and not isattribute(self,"test")
                        see "add attribute" + nl
                        addattribute(self,"test")
                        test = 10
                ok
                see "done" + nl
                return

Output:

Handle Error!
Message :Error (R24) : Using uninitialized variable : test
add attribute
done
10

Example:

new point {
        x=10 y=20 z=30
        test()
        see "mmm..." + NL
}

class point x y z
        func braceerror
                see "Handle Error!" + nl
                see "Message :" + cCatchError + nl
                see self
                see "Done" + NL

Output:

Handle Error!
Message :Error (R3) : Calling Function without definition !: test
x: 10.000000
y: 20.000000
z: 30.000000
Done
mmm...

Clean Natural Code

Instead of typing the literal as “literal”, we can accept the words directly.

Example:

The next example accepts hello world instead of “hello world”:

ChangeRingKeyword       and  _and
ChangeRingOperator      =    is

New App
{
        I want window and the window title is hello world
}

ChangeRingOperator      is    =

Class App

        # Attributes for the instruction I want window
                        i want window
                        nIwantwindow = 0
        # Attributes for the instruction Window title
        # Here we don't define the window attribute again
                        title
                        nWindowTitle = 0
        # Keywords to ignore, just give them any value
                        the=0  and=0
        # Data
                        literal = ""

ChangeRingKeyword       _and  and

        func geti
                if nIwantwindow = 0
                        nIwantwindow++
                ok

        func getwant
                if nIwantwindow = 1
                        nIwantwindow++
                ok

        func getwindow
                if nIwantwindow = 2
                        nIwantwindow= 0
                        see "Instruction : I want window" + nl
                ok
                if nWindowTitle = 0
                        nWindowTitle++
                ok

        func settitle cValue
                if nWindowTitle = 1
                        nWindowTitle=2
                ok

        func braceend
                if nWindowTitle = 2
                        see "Instruction : Window Title = " + literal + nl
                        nWindowTitle = 0
                ok

        func braceerror
                c= substr(cCatchError,":")
                while c > 0
                        c= substr(cCatchError,":")
                        cCatchError=substr(cCatchError,c+1)
                end
                literal += substr(cCatchError,1)

Points of Interest

In 2010, I developed the Supernova language in 9 months. Now using Ring, I can implement a language like Supernova in a few days. The ability to define natural languages based on classes instead of creating a compiler is a big deal. This increases the productivity and decreases the complexity of the problem. You can create large natural programming language and still control the project. Think of implementing your next natural programming language using Ring!

History

  • 13th October, 2016: Initial version

There is a lot of work done in Natural Programming Languages. The Ring programming language is a practical programming language that tries to push Natural Language Programming a step forward. Ring is a new language released on 2016.01.25.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)