Pāṇinian Grammar: Part 6 - Introduction to Programming
This series of articles is dedicated to Pāṇinian grammar of the Saṃskṛta language, as presented in his treatise “Aṣṭādhyāyī”. In trying to characterize the grammar of the Saṃskṛta language spoken in his day, Pāṇini Maharṣi manufactures legitimate and only legitimate words of the Saṃskṛta language, by designing a set of 4000 rules in a highly compressed language of the “sūtra” that operates on the sounds, verb roots, prefixes and suffixes, to generate all the words of Saṃskṛta language.
In this process, Pāṇini uses techniques from modern computing (especially the theory of formal languages that are used in analysis and compiler design for programming languages) and anticipates them even though it would be 2500 years from his time when the first actual computer would be invented. Techniques like optimal ordering of data, information compression, metalanguage, metarules, use of non-terminal symbols, light before heavy are all used in this masterpiece.
To study the Aṣṭādhyāyī, it is essential to know the Saṃskṛta language, as that is the language for which the grammar is designed. However in this series, my aim is to introduce how Pāṇini uses these techniques in his treatise for people who don’t have any knowledge of the Saṃskṛta language, or formal language theory in computer science. I also present the rich developments in the philosophy of language that Pāṇini’s work inspired in his successors and compare it with Western philosophies of language like that of Russell, Wittgenstein, de Saussure, etc.
Language was an important concern in ancient Indian philosophy, especially for the Āstika schools, as they believed that the efficacy of the Vedic rituals directly depended on the sounds of the chanted mantras. They wanted to justify how this efficacy is brought about, and in the process, they had to analyze how the sounds of a language relate to meaning and ultimately reality itself. By the end of this series, you will have a deep appreciation of the importance, depth and scope of Aṣṭādhyāyī and the Indian views on language.
If you are a computer scientist and programming is your day job, you can safely skip this and the next section. I am not a computer scientist either - I am so bad at coding. But what I am going to say is more about problem solving than it is about the exact coding. Hence, it is okay if you do not understand all the exact details in your head. Read through this section where I introduce in as simple terms as possible, the various concepts of object oriented programming and its uses. In the next section, I will connect all these concepts to Pāṇinian grammar and how he brilliantly uses them in his Aṣṭādhyāyī.
Let us consider a very simple problem - to check whether a given positive integer is even or odd. This is how a program for that will look like in the C++ programming language - don’t be scared if you did not study computer science (I also did not), but just watch it and I will explain it step by step.
include <iostream>
using namespace std;
int main() {
int n;
cout << "Enter an integer: ";
cin >> n;
if ( n % 2 == 0)
cout << n << " is even.";
else
cout >> m >> " is odd.";
}
Now, let me explain this program. The first two lines are routine stuff that need to be typed for every program. The core part starts with the main block. Let us focus between the int main { } thing.
int n;
The symbol “int” here is an abbreviation for integer and the line int n; defines that a variable named n is an integer. This is the number that the user is going to enter and have it checked for even or odd. So this line defines the name and nature of the data that the user is going to enter - which is an integer named “n”. So, this line in the code is not doing anything but only defining things that are going to be involved in the task that is going to be solved by an algorithm. The line:
cout << "Enter an integer: ";
is an output that comes from the computer to the user. The computer here is being asked or programmed to give an output that prompts the user to enter an integer. Upon seeing this message, the user will enter the positive integer. Now, coming to the next line.
cin >> n;
After the user has entered the positive integer, this line in the code is instructing the computer to take the data he entered as the positive integer “n” that he wants to be checked as even or odd. Now, coming to the core task. Look at the following lines
if ( n % 2 == 0)
cout << n << " is even.";
else
cout << n << " is odd.";
Here, the symbol “%” is the remainder operator - i.e. “a%b” is the remainder obtained by dividing “a” by “b”. So, n%2 will give the remainder that is obtained when the integer n is divided by 2. Now when any integer is divided by 2, it is either 0 or 1. The line above tells us that if the remainder obtained in the operation n%2 is 0, then output to the user that the number n is even. Or else, output and prompt the user that the number n is odd. This is a very simple problem. We all know that a number is even if and only if the remainder obtained after dividing it by 2 is zero and odd otherwise. But there are technical names for certain things that are seen in this code.
Reserved keyword:
The abbreviation int that stands for a positive integer is called a keyword in a computer program. This abbreviation cannot be used to name any other variable and is reserved and defined by the programming language system itself - you cannot name any other entity in your program by these abbreviations like int that are already reserved by the programming language (in this case C++) for something else.
Standard function:
The symbol % is also reserved by the system for a specific purpose - from what I have told you, it is the remainder operation. Such standard operations that are defined already in the programming languages are called standard functions. The % operator takes two positive integers, divides the first one by the second and outputs the reminder of the result obtained. Again, this remainder function with its symbol % is already reserved by the system. The system already knows everything that this % operator does. It knows
What it takes in as its input - in this case, two positive integers
What it does to the input - in this case, compute the remainder of the first divided by second
What it returns or gives back - in this case, return the remainder obtained
Now, let us execute the same task in a slightly different way - using the concept of user-defined functions. Read the code below. Here, in the main part of the code, I have called upon a strange operation that I have created on my own - it is called evenoddcheck. It takes an integer, divides it by 2 and returns the remainder. Using this I rewrite the code as follows:
include <iostream>
using namespace std;
int evenoddcheck(int n);
int main() {
int n;
cout << "Enter an integer: ";
cin >> n;
if(evenoddcheck(n)==0)
cout << n << " is even.";
else
cout << n << " is odd.";
}
But how will the computer know what this strange operation evenoddcheck stands for? It turns out that after the program, I need to type what the function does and define it completely. That definition follows outside of the main bracket int main {....} and is given below.
int evenoddcheck(int n) {
int result;
if(n%2==0)
result=0;
else
result=1;
return result;
}
Here, let me explain the function definition step by step. The first line of the code is
int evenoddcheck(int n) { ... }
Here, the part evenoddcheck is the name I assign to the function. In the bracket that has (int n), I tell that this function has to take an integer named n as the input. In the first word int, I tell that the output of the function is also another integer - in this case, the remainder obtained when the integer n is divided by 2. The rest part inside is the standard computation of the remainder.
Now what difference is achieved? By rewriting the remainder by 2 computations separately. The thing is that I can use this function readily whenever I want in the main program instead of typing it all again. It may not mean much for simple operations as in here but a lot for more complex operations. I can define all the complicated operations that I am going to use separately and my main program will be clean and call readily just what I want.
This introduction is needed for the next part, where we will gain a specific introduction to Object Oriented Programming.
Authored by Rama Seshan Chandra Sekaran. Published by Brhat.