Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using the Natural Language Programming Library (NLPL) in the Ring Programming Language

5.00/5 (5 votes)
11 Aug 2017CPOL4 min read 20.1K   91  
Practical introduction to using the Natural Language Programming Library in the Ring programming language version 1.4.1

Introduction

There are many programming paradigms like Imperative, Procedural, Object-Oriented and Functional programming. In this wikipedia article, you can read about them. In this article, I will talk about how to use the Natural Language Programming Paradigm in the Ring programming language. After reading this article, you will become ready to create a new language that uses Natural Language Programming.

Background

You can read the following articles:

  1. The Ring Programming Language
  2. Natural Language Programming in the Ring programming language

Using the Code

The Ring language comes with a library for Natural Language Programming. To use the library, at the start, you have to load it first.

load "naturallib.ring"

We will write the natural code in a Text file, for example, program.txt.

When we say Hello to the Machine, It can reply! and when we 
say count from 1 to 5 it will understand us, Also if we said count from 5 to 1 it will
understand us too!

We expect the next output:

Hello, Sir!


The Numbers!
1
2
3
4
5

I will count Again!
5
4
3
2
1

As you can see, we start programming by typing the problem definition, think of this as writing requirements in a language that we can understand and implement but very near to the problem domain where non-programmers can understand it too.

Now to execute the natural code, we will create a new Ring source code file: start.ring.

In start.ring, we will define the language and the commands.

File: start.ring

C++
load "stdlib.ring"
load "naturallib.ring"

New NaturalLanguage {
        SetLanguageName(:MyLanguage)
        SetCommandsPath(CurrentDir()+"/../command")
        SetPackageName("MyLanguage.Natural")
        UseCommand(:Hello)
        UseCommand(:Count)
        RunFile("program.txt")
}

The NaturalLanguage class contains the following methods:

  • SetLanguageName(cLanguageName)
  • setCommandsPath(cFolder)
  • SetPackageName(cPackageName)
  • UseCommand(cCommandName)
  • SetOperators(cOperators)
  • RunFile(cFileName)
  • RunString(cString)

Using these methods, we defined a language called MyLanguage. We have a folder for the language commands.

Each command will define a class that belongs to the MyLanguage.Natural package.

We will define two commands, Hello and Count.

So we must have two files for defining the commands in the CurrentDir()+”/../command” folder.

To define new command, we can use the DefineNaturalCommand object.

This object provides the following methods:

  • SyntaxIsKeyword(aPara)
  • SyntaxIsKeywordNumber(aPara)
  • SyntaxIsKeywordNumberNumber(aPara)
  • SyntaxIsKeywordNumbers(aPara,nCount)
  • SyntaxIsKeywordString(aPara)
  • SyntaxIsKeywordStringString(aPara)
  • SyntaxIsKeywordStrings(aPara,nCount)
  • SyntaxIsKeywordExpression(aPara)
  • SyntaxIsKeywordExpressionExpression(aPara)
  • SyntaxIsKeywordExpressions(aPara,nCount)
  • SyntaxIsCommand(aPara)
  • SyntaxIsCommandNumber(aPara)
  • SyntaxIsCommandNumberNumber(aPara)
  • SyntaxIsCommandNumbers(aPara,nCount)
  • SyntaxIsCommandString(aPara)
  • SyntaxIsCommandStringString(aPara)
  • SyntaxIsCommandStrings(aPara,nCount)
  • SyntaxIsCommandExpression(aPara)
  • SyntaxIsCommandExpressionExpression(aPara)
  • SyntaxIsCommandExpressions(aPara,nCount)

File: hello.ring

DefineNaturalCommand.SyntaxIsKeyword([
        :Package = "MyLanguage.Natural",
        :Keyword = :hello,
        :Function = func {
                See  "Hello, Sir!" + nl + nl
        }
])

To defined the Hello command, we used the SyntaxIsKeyword() method in the DefineNaturalCommand object.

DefineNaturalCommand is an object from the Natural Library class.

We passed three parameters to define the command (Package Name, Keyword & Anonymous function).

File: count.ring

DefineNaturalCommand.SyntaxIsKeywordNumberNumber([
        :Package = "MyLanguage.Natural",
        :Keyword = :count,
        :Function = func {
                if not isattribute(self,:count_times) {
                        AddAttribute(self,:count_times)
                        Count_Times = 0
                }
                if Expr(1) > Expr(2) {
                        nStep = -1
                else
                        nStep = 1
                }
                if Count_Times = 0 {
                        see nl+"The Numbers!" + nl
                        Count_Times++
                else
                        see nl + "I will count Again!" +nl
                }
                for x = Expr(1) to Expr(2) step nStep {
                        see nl+x+nl
                }
                CommandReturn(fabs(Expr(1)-Expr(2))+1)
        }
])

To define the Count command, we have used the SyntaxIsKeywordNumberNumber() method.

This method accept three parameters:

  1. The package Name: We selected "MyLanguage.Natural" as our package name
  2. The Keyword: It's "Count" and we can write it as :count to get the same result
  3. Anonymous Function: Will be executed when we have the Count command

Inside the Anonymous Function, we used Expr() method to get the values after the Count command

  • Expr(1) ---> The first expression (Number) after the command
  • Expr(2) ----> The second expression (Number) after the command.

We use isattribute() and addattribute() functions to add an attribute to be used in our anonymous function.

We defined <span class="p">:</span>count_times attributes, it's value is 0.

if not isattribute(self,:count_times) {
  AddAttribute(self,:count_times)
  Count_Times = 0
}

Using this attribute, we can know if we are counting for the first time or the second time.

if Count_Times = 0 {
    see nl+"The Numbers!" + nl
    Count_Times++
else
    see nl + "I will count Again!" +nl
}

We will determine the count direction (from low to high or from high to low) based on the expressions values.

if Expr(1) > Expr(2) {
    nStep = -1
else
    nStep = 1
}

To return the output from the anonymous function to the Natural Library, we use the CommandReturn() method.

We need this output if we have nested commands, but in our example, it's not important.

CommandReturn(fabs(Expr(1)-Expr(2))+1)

Let us test our work. Add more text for fun (don't do that in real programs!).

Image 1

Points of Interest

When we program using this way, we get:

  1. Very high level of readability
  2. Our users can easily understand our programs
  3. Requirements become part of the implementation (Real Code)
  4. Users can modify programs based on new requirements that can be expressed using the same language as previous requirements
  5. The Ring programming language lets us focus on using the Natural Language Programming paradigm without thinking about the hard technical details like correctness, parsing & performance
  6. It's a research topic, you can do a Masters or PhD in this area if you have new ideas and results
  7. Since the Natural Code is very small, and close to the problem, this reduces programming errors and increases productivity

History

The Ring is an innovative and practical general-purpose multi-paradigm language:

  • In November 2011, the idea of the new language was conceived
  • In Sept. 2013, the design and the implementation of the Ring programming language is started
  • In April 2015, the language name is selected
  • In May 2015, the Compiler was implemented
  • In Sept. 2015, the Documentation was done
  • In January 2016, the Ring 1.0 was released
  • In October 2016, the Ring 1.1 was released
  • In January 25, 2017, the Ring 1.2 was released
  • In May 15, 2017, the Ring 1.3 was released
  • In June 29, 2017, the Ring 1.4 was released
  • In July 11, 2017, the Ring 1.4.1 was released

License

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