UNIT 6
Logical and Functional Programming
Functional programming languages are specially designed to handle symbolic computation and list processing applications. Functional programming is based on mathematical functions. Some of the popular functional programming languages include: Lisp, Python, Erlang, Haskell, Clojure, etc.
Functional programming languages are categorized into two groups, i.e. −
Functional Programming – Characteristics
The most prominent characteristics of functional programming are as follows −
Functional Programming – Advantages
Functional programming offers the following advantages −
As a downside, functional programming requires a large memory space. As it does not have state, you need to create new objects every time to perform actions.
Functional Programming is used in situations where we have to perform lots of different operations on the same set of data.
Functional Programming vs. Object-oriented Programming
The following table highlights the major differences between functional programming and object-oriented programming −
Functional Programming | OOP |
Uses Immutable data. | Uses Mutable data. |
Follows Declarative Programming Model. | Follows Imperative Programming Model. |
Focus is on: “What you are doing” | Focus is on “How you are doing” |
Supports Parallel Programming | Not suitable for Parallel Programming |
Its functions have no-side effects | Its methods can produce serious side effects. |
Flow Control is done using function calls & function calls with recursion | Flow control is done using loops and conditional statements. |
It uses "Recursion" concept to iterate Collection Data. | It uses "Loop" concept to iterate Collection Data. For example: For-each loop in Java |
Execution order of statements is not so important. | Execution order of statements is very important. |
Supports both "Abstraction over Data" and "Abstraction over Behavior". | Supports only "Abstraction over Data". |
The efficiency of a programming code is directly proportional to the algorithmic efficiency and the execution speed. Good efficiency ensures higher performance.
The factors that affect the efficiency of a program includes −
The efficiency of a programming language can be improved by performing the following tasks −
An efficient programming code can reduce resource consumption and completion time as much as possible with minimum risk to the operating environment.
Key takeaway
Functional programming languages are specially designed to handle symbolic computation and list processing applications. Functional programming is based on mathematical functions. Some of the popular functional programming languages include: Lisp, Python, Erlang, Haskell, Clojure, etc.
Functional programming languages are categorized into two groups, i.e. −
John McCarthy invented LISP in 1958, shortly after the development of FORTRAN. It was first implemented by Steve Russell on an IBM 704 computer.
It is particularly suitable for Artificial Intelligence programs, as it processes symbolic information effectively.
Common Lisp originated, during the 1980s and 1990s, in an attempt to unify the work of several implementation groups that were successors to Maclisp, like ZetaLisp and NIL (New Implementation of Lisp) etc.
It serves as a common language, which can be easily extended for specific implementation.
Programs written in Common LISP do not depend on machine-specific characteristics, such as word length etc.
Large successful applications built in Lisp.
If you are still willing to set up your environment for Lisp programming language, you need the following two softwares available on your computer, (a) Text Editor and (b) The Lisp Executer.
This will be used to type your program. Examples of few editors include Windows Notepad, OS Edit command, Brief, Epsilon, EMACS, and vim or vi.
Name and version of text editor can vary on different operating systems. For example, Notepad will be used on Windows, and vim or vi can be used on windows as well as Linux or UNIX.
The files you create with your editor are called source files and contain program source code. The source files for Lisp programs are typically named with the extension ".lisp".
Before starting your programming, make sure you have one text editor in place and you have enough experience to write a computer program, save it in a file, finally execute it.
The source code written in source file is the human readable source for your program. It needs to be "executed", to turn into machine language so that your CPU can actually execute the program as per instructions given.
This Lisp programming language will be used to execute your source code into final executable program. I assume you have basic knowledge about a programming language.
CLISP is the GNU Common LISP multi-architechtural compiler used for setting up LISP in Windows. The windows version emulates a unix environment using MingW under windows. The installer takes care of this and automatically adds clisp to the windows PATH variable.
Fig 1 - GNU Common LISP
It creates a shortcut in the Start Menu by default, for the line-by-line interpreter.
During installation, clisp is automatically added to your PATH variable if you select the option (RECOMMENDED) This means that you can simply open a new Command Prompt window and type “clisp” to bring up the compiler.
To run a *.lisp or *.lsp file, simply use −
clisp hello.lisp
Decision making structures require that the programmer specify one or more conditions to be evaluated or tested by the program, along with a statement or statements to be executed if the condition is determined to be true, and optionally, other statements to be executed if the condition is determined to be false.
Following is the general form of a typical decision making structure found in most of the programming languages −
Fig 2 - Typical decision-making structure
LISP provides following types of decision-making constructs. Click the following links to check their detail.
Sr.No. | Construct & Description |
1 | Cond This construct is used for used for checking multiple test-action clauses. It can be compared to the nested if statements in other programming languages. |
2 | If The if construct has various forms. In simplest form it is followed by a test clause, a test action and some other consequent action(s). If the test clause evaluates to true, then the test action is executed otherwise, the consequent clause is evaluated. |
3 | when In simplest form it is followed by a test clause, and a test action. If the test clause evaluates to true, then the test action is executed otherwise, the consequent clause is evaluated. |
4 | Case This construct implements multiple test-action clauses like the cond construct. However, it evaluates a key form and allows multiple action clauses based on the evaluation of that key form. |
There may be a situation, when you need to execute a block of code numbers of times. A loop statement allows us to execute a statement or group of statements multiple times and following is the general form of a loop statement in most of the programming languages.
Fig 3 - loop statement
LISP provides the following types of constructs to handle looping requirements. Click the following links to check their detail.
Sr.No. | Construct & Description |
1 | Loop The loop construct is the simplest form of iteration provided by LISP. In its simplest form, it allows you to execute some statement(s) repeatedly until it finds a return statement. |
2 | loop for The loop for construct allows you to implement a for-loop like iteration as most common in other languages. |
3 | Do The do construct is also used for performing iteration using LISP. It provides a structured form of iteration. |
4 | dotimes The dotimes construct allows looping for some fixed number of iterations. |
5 | dolist The dolist construct allows iteration through each element of a list. |
Gracefully Exiting From a Block
The block and return-from allows you to exit gracefully from any nested blocks in case of any error.
The block function allows you to create a named block with a body composed of zero or more statements. Syntax is −
(block block-name(
...
...
))
The return-from function takes a block name and an optional (the default is nil) return value.
The following example demonstrates this −
Create a new source code file named main.lisp and type the following code in it −
(defun demo-function (flag)
(print 'entering-outer-block)
(block outer-block
(print 'entering-inner-block)
(print (block inner-block
(if flag
(return-from outer-block 3)
(return-from inner-block 5)
)
(print 'This-wil--not-be-printed))
)
(print 'left-inner-block)
(print 'leaving-outer-block)
t)
)
(demo-function t)
(terpri)
(demo-function nil)
When you click the Execute button, or type Ctrl+E, LISP executes it immediately and the result returned is −
ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
5
LEFT-INNER-BLOCK
LEAVING-OUTER-BLOCK
A function is a group of statements that together perform a task.
You can divide up your code into separate functions. How you divide up your code among different functions is up to you, but logically the division usually is so each function performs a specific task.
The macro named defun is used for defining functions. The defun macro needs three arguments −
Syntax for defun is −
(defun name (parameter-list) "Optional documentation string." body)
Let us illustrate the concept with simple examples.
Let's write a function named averagenum that will print the average of four numbers. We will send these numbers as parameters.
Create a new source code file named main.lisp and type the following code in it.
(defun averagenum (n1 n2 n3 n4)
(/ ( + n1 n2 n3 n4) 4)
)
(write(averagenum 10 20 30 40))
When you execute the code, it returns the following result −
25
Let's define and call a function that would calculate the area of a circle when the radius of the circle is given as an argument.
Create a new source code file named main.lisp and type the following code in it.
(defun area-circle(rad)
"Calculates area of a circle with given radius"
(terpri)
(format t "Radius: ~5f" rad)
(format t "~%Area: ~10f" (* 3.141592 rad rad))
)
(area-circle 10)
When you execute the code, it returns the following result −
Radius: 10.0
Area: 314.1592
Please note that −
Predicates are functions that test their arguments for some specific conditions and returns nil if the condition is false, or some non-nil value is the condition is true.
The following table shows some of the most commonly used predicates −
Sr.No. | Predicate & Description |
1 | Atom It takes one argument and returns t if the argument is an atom or nil if otherwise. |
2 | Equal It takes two arguments and returns t if they are structurally equal or nil otherwise. |
3 | Eq It takes two arguments and returns t if they are same identical objects, sharing the same memory location or nil otherwise. |
4 | Eql It takes two arguments and returns t if the arguments are eq, or if they are numbers of the same type with the same value, or if they are character objects that represent the same character, or nil otherwise. |
5 | Evenp It takes one numeric argument and returns t if the argument is even number or nil if otherwise. |
6 | Oddp It takes one numeric argument and returns t if the argument is odd number or nil if otherwise. |
7 | Zerop It takes one numeric argument and returns t if the argument is zero or nil if otherwise. |
8 | Null It takes one argument and returns t if the argument evaluates to nil, otherwise it returns nil. |
9 | Listp It takes one argument and returns t if the argument evaluates to a list otherwise it returns nil. |
10 | Greaterp It takes one or more argument and returns t if either there is a single argument or the arguments are successively larger from left to right, or nil if otherwise. |
11 | Lessp It takes one or more argument and returns t if either there is a single argument or the arguments are successively smaller from left to right, or nil if otherwise. |
12 | Numberp It takes one argument and returns t if the argument is a number or nil if otherwise. |
13 | Symbol It takes one argument and returns t if the argument is a symbol otherwise it returns nil. |
14 | Integer It takes one argument and returns t if the argument is an integer otherwise it returns nil. |
15 | Rationalp It takes one argument and returns t if the argument is rational number, either a ratio or a number, otherwise it returns nil. |
16 | Floatp It takes one argument and returns t if the argument is a floating point number otherwise it returns nil. |
17 | Realp It takes one argument and returns t if the argument is a real number otherwise it returns nil. |
18 | Complex It takes one argument and returns t if the argument is a complex number otherwise it returns nil. |
19 | Character It takes one argument and returns t if the argument is a character otherwise it returns nil. |
20 | Stringp It takes one argument and returns t if the argument is a string object otherwise it returns nil. |
21 | Arrayp It takes one argument and returns t if the argument is an array object otherwise it returns nil. |
22 | Packagep It takes one argument and returns t if the argument is a package otherwise it returns nil. |
Create a new source code file named main.lisp and type the following code in it.
(write (atom 'abcd))
(terpri)
(write (equal 'a 'b))
(terpri)
(write (evenp 10))
(terpri)
(write (evenp 7 ))
(terpri)
(write (oddp 7 ))
(terpri)
(write (zerop 0.0000000001))
(terpri)
(write (eq 3 3.0 ))
(terpri)
(write (equal 3 3.0 ))
(terpri)
(write (null nil ))
When you execute the code, it returns the following result −
T
NIL
T
NIL
T
NIL
NIL
NIL
T
Create a new source code file named main.lisp and type the following code in it.
(defun factorial (num)
(cond ((zerop num) 1)
(t ( * num (factorial (- num 1))))
)
)
(setq n 6)
(format t "~% Factorial ~d is: ~d" n (factorial n))
When you execute the code, it returns the following result −
Factorial 6 is: 720
Key takeaway
John McCarthy invented LISP in 1958, shortly after the development of FORTRAN. It was first implemented by Steve Russell on an IBM 704 computer.
It is particularly suitable for Artificial Intelligence programs, as it processes symbolic information effectively.
Common Lisp originated, during the 1980s and 1990s, in an attempt to unify the work of several implementation groups that were successors to Maclisp, like ZetaLisp and NIL (New Implementation of Lisp) etc.
It serves as a common language, which can be easily extended for specific implementation.
Programs written in Common LISP do not depend on machine-specific characteristics, such as word length etc.
The Recursion and Iteration both repeatedly execute the set of instructions. Recursion is when a statement in a function calls itself repeatedly. The iteration is when a loop repeatedly executes until the controlling condition becomes false. The primary difference between recursion and iteration is that recursion is a process, always applied to a function and iteration is applied to the set of instructions which we want to get repeatedly executed.
public class RecursionExample {
public static void main(String args[]) {
RecursionExample re = new RecursionExample();
int result = re.factorial(4);
System.out.println("Result:" + result);
}
public int factorial(int n) {
if (n==0) {
return 1;
}
else {
return n*factorial(n-1);
}
}
}
Result:24
public class IterationExample {
public static void main(String args[]) {
for(int i = 1; i <= 5; i++) {
System.out.println(i + " ");
}
}
}
1
2
3
4
5
Key takeaway
The Recursion and Iteration both repeatedly execute the set of instructions. Recursion is when a statement in a function calls itself repeatedly. The iteration is when a loop repeatedly executes until the controlling condition becomes false. The primary difference between recursion and iteration is that recursion is a process, always applied to a function and iteration is applied to the set of instructions which we want to get repeatedly executed.
The properties object contains key and value pair both as a string. The java.util.Properties class is the subclass of Hashtable.
It can be used to get property value based on the property key. The Properties class provides methods to get data from the properties file and store data into the properties file. Moreover, it can be used to get the properties of a system.
An Advantage of the properties file
Recompilation is not required if the information is changed from a properties file: If any information is changed from the properties file, you don't need to recompile the java class. It is used to store information which is to be changed frequently.
Constructors of Properties class
Method | Description |
Properties() | It creates an empty property list with no default values. |
Properties(Properties defaults) | It creates an empty property list with the specified defaults. |
The commonly used methods of Properties class are given below.
Method | Description |
public void load(Reader r) | It loads data from the Reader object. |
public void load(InputStream is) | It loads data from the InputStream object |
public void loadFromXML(InputStream in) | It is used to load all of the properties represented by the XML document on the specified input stream into this properties table. |
public String getProperty(String key) | It returns value based on the key. |
public String getProperty(String key, String defaultValue) | It searches for the property with the specified key. |
public void setProperty(String key, String value) | It calls the put method of Hashtable. |
public void list(PrintStream out) | It is used to print the property list out to the specified output stream. |
public void list(PrintWriter out)) | It is used to print the property list out to the specified output stream. |
public Enumeration<?> propertyNames()) | It returns an enumeration of all the keys from the property list. |
public Set<String> stringPropertyNames() | It returns a set of keys in from property list where the key and its corresponding value are strings. |
public void store(Writer w, String comment) | It writes the properties in the writer object. |
public void store(OutputStream os, String comment) | It writes the properties in the OutputStream object. |
public void storeToXML(OutputStream os, String comment) | It writes the properties in the writer object for generating XML document. |
public void storeToXML(Writer w, String comment, String encoding) | It writes the properties in the writer object for generating XML document with the specified encoding. |
Example of Properties class to get information from the properties file
To get information from the properties file, create the properties file first.
db.properties
Now, let's create the java class to read the data from the properties file.
Test.java
Output:system
oracle
Now if you change the value of the properties file, you don't need to recompile the java class. That means no maintenance problem.
Example of Properties class to get all the system properties
By System.getProperties() method we can get all the properties of the system. Let's create the class that gets information from the system properties.
Test.java
Output:
java.runtime.name = Java(TM) SE Runtime Environment
sun.boot.library.path = C:\Program Files\Java\jdk1.7.0_01\jre\bin
java.vm.version = 21.1-b02
java.vm.vendor = Oracle Corporation
java.vendor.url = http://java.oracle.com/
path.separator = ;
java.vm.name = Java HotSpot(TM) Client VM
file.encoding.pkg = sun.io
user.country = US
user.script =
sun.java.launcher = SUN_STANDARD
...........
Example of Properties class to create the properties file
Now let's write the code to create the properties file.
Test.java
Let's see the generated properties file.
info.properties
Key takeaway
The properties object contains key and value pair both as a string. The java.util.Properties class is the subclass of Hashtable.
It can be used to get property value based on the property key. The Properties class provides methods to get data from the properties file and store data into the properties file. Moreover, it can be used to get the properties of a system.
Lambda expressions basically express instances of functional interfaces (An interface with single abstract method is called functional interface. An example is java.lang.Runnable). lambda expressions implement the only abstract function and therefore implement functional interfaces
lambda expressions are added in Java 8 and provide below functionalities.
// Java program to demonstrate lambda expressions // to implement a user defined functional interface.
// A sample functional interface (An interface with // single abstract method interface FuncInterface { // An abstract function void abstractFun(int x);
// A non-abstract (or default) function default void normalFun() { System.out.println("Hello"); } }
class Test { public static void main(String args[]) { // lambda expression to implement above // functional interface. This interface // by default implements abstractFun() FuncInterface fobj = (int x)->System.out.println(2*x);
// This calls above lambda expression and prints 10. fobj.abstractFun(5); } } |
Output:
10
Fig 4 – Example
Syntax:
lambda operator -> body
where lambda operator can be:
() -> System.out.println("Zero parameter lambda");
(p) -> System.out.println("One parameter: " + p);
It is not mandatory to use parentheses, if the type of that variable can be inferred from the context
(p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2);
Please note: Lambda expressions are just like functions and they accept parameters just like functions.
// A Java program to demonstrate simple lambda expressions import java.util.ArrayList; class Test { public static void main(String args[]) { // Creating an ArrayList with elements // {1, 2, 3, 4} ArrayList<Integer> arrL = new ArrayList<Integer>(); arrL.add(1); arrL.add(2); arrL.add(3); arrL.add(4);
// Using lambda expression to print all elements // of arrL arrL.forEach(n -> System.out.println(n));
// Using lambda expression to print even elements // of arrL arrL.forEach(n -> { if (n%2 == 0) System.out.println(n); }); } } |
Output :
1
2
3
4
2
4
Note that lambda expressions can only be used to implement functional interfaces. In the above example also, the lambda expression implements Consumer Functional Interface.
A Java program to demonstrate working of lambda expression with two arguments.
// Java program to demonstrate working of lambda expressions public class Test { // operation is implemented using lambda expressions interface FuncInter1 { int operation(int a, int b); }
// sayMessage() is implemented using lambda expressions // above interface FuncInter2 { void sayMessage(String message); }
// Performs FuncInter1's operation on 'a' and 'b' private int operate(int a, int b, FuncInter1 fobj) { return fobj.operation(a, b); }
public static void main(String args[]) { // lambda expression for addition for two parameters // data type for x and y is optional. // This expression implements 'FuncInter1' interface FuncInter1 add = (int x, int y) -> x + y;
// lambda expression multiplication for two parameters // This expression also implements 'FuncInter1' interface FuncInter1 multiply = (int x, int y) -> x * y;
// Creating an object of Test to call operate using // different implementations using lambda Expressions Test tobj = new Test();
// Add two numbers using lambda expression System.out.println("Addition is " + tobj.operate(6, 3, add));
// Multiply two numbers using lambda expression System.out.println("Multiplication is " + tobj.operate(6, 3, multiply));
// lambda expression for single parameter // This expression implements 'FuncInter2' interface FuncInter2 fobj = message ->System.out.println("Hello " + message); fobj.sayMessage("Geek"); } } |
Output:
Addition is 9
Multiplication is 18
Hello Geek
Important points:
Key takeaway
Lambda expressions basically express instances of functional interfaces (An interface with single abstract method is called functional interface. An example is java.lang.Runnable). lambda expressions implement the only abstract function and therefore implement functional interfaces
lambda expressions are added in Java 8 and provide below functionalities.
Prolog is a logic programming language. It has important role in artificial intelligence. Unlike many other programming languages, Prolog is intended primarily as a declarative programming language. In prolog, logic is expressed as relations (called as Facts and Rules). Core heart of prolog lies at the logic being applied. Formulation or Computation is carried out by running a query over these relations.
Installation in Linux :
Open a terminal (Ctrl+Alt+T) and type:
sudo apt-get install swi-prolog
Syntax and Basic Fields :
In prolog, We declare some facts. These facts constitute the Knowledge Base of the system. We can query against the Knowledge Base. We get output as affirmative if our query is already in the knowledge Base or it is implied by Knowledge Base, otherwise we get output as negative. So, Knowledge Base can be considered similar to database, against which we can query. Prolog facts are expressed in definite pattern. Facts contain entities and their relation. Entities are written within the parenthesis separated by comma (, ). Their relation is expressed at the start and outside the parenthesis. Every fact/rule ends with a dot (.). So, a typical prolog fact goes as follows :
Format : relation(entity1, entity2, ....k'th entity).
Example :
friends(raju, mahesh).
singer(sonu).
odd_number(5).
Explanation :
These facts can be interpreted as :
raju and mahesh are friends.
sonu is a singer.
5 is an odd number.
Key Features :
1. Unification : The basic idea is, can the given terms be made to represent the same structure.
2. Backtracking : When a task fails, prolog traces backwards and tries to satisfy previous task.
3. Recursion : Recursion is the basis for any search in program.
Running queries :
A typical prolog query can be asked as :
Query 1 : ?- singer(sonu).
Output : Yes.
Explanation : As our knowledge base contains
the above fact, so output was 'Yes', otherwise
it would have been 'No'.
Query 2 : ?- odd_number(7).
Output : No.
Explanation : As our knowledge base does not
contain the above fact, so output was 'No'.
Advantages :
1. Easy to build database. Doesn’t need a lot of programming effort.
2. Pattern matching is easy. Search is recursion based.
3. It has built in list handling. Makes it easier to play with any algorithm involving lists.
Disadvantages :
1. LISP (another logic programming language) dominates over prolog with respect to I/O features.
2. Sometimes input and output is not easy.
Applications :
Prolog is highly used in artificial intelligence(AI). Prolog is also used for pattern matching over natural language parse trees.
Key takeaway
Prolog is a logic programming language. It has important role in artificial intelligence. Unlike many other programming languages, Prolog is intended primarily as a declarative programming language. In prolog, logic is expressed as relations (called as Facts and Rules). Core heart of prolog lies at the logic being applied. Formulation or Computation is carried out by running a query over these relations.
Installation in Linux :
Open a terminal (Ctrl+Alt+T) and type:
sudo apt-get install swi-prolog
Prolog is a logic language, not an algorithmic language, and one therefore has to learn to think about programs in a somewhat different way. The terminology is also somewhat different.
The following is a simple Prolog program:
man(socrates).
mortal(X) :- man(X).
The first line can be read, "Socrates is a man.'' It is a base clause, which represents a simple fact.
The second line can be read, "X is mortal if X is a man;'' in other words, "All men are mortal.'' This is a clause, or rule, for determining when its input X is "mortal.'' (The symbol ":-'', sometimes called a turnstile, is pronounced "if''.) We can test the program by asking the question:
| ?- mortal(socrates).
that is, "Is Socrates mortal?'' (The "| ?-'' is the computer's prompt for a question.) Prolog will respond "yes''. Another question we may ask is:
| ?- mortal(X).
That is, "Who (X) is mortal?'' Prolog will respond "X = socrates''.
A program, or database, in Prolog consists of one or more predicates; each predicate consists of one or more clauses. A clause is a base clause if it is unconditionally true, that is, it has no "if part.''
<program> ::= <predicate> | <program><predicate>
<predicate> ::= <clause> | <predicate><clause>
<clause> ::= <base clause> | <nonbase clause>
Two clauses belong to the same predicate if they have the same functor (name) and the same arity (number of arguments). Thus, mother(jane) and mother(jane, jim) are different predicates.
<base clause> ::= <structure> .
<nonbase clause> ::= <structure> :- <structures> .
<structures> ::= <structure> | <structure> , <structures>
A structure is a functor followed by zero or more arguments; the arguments are enclosed in parentheses and separated by commas. There must be no space between the functor and the opening parenthesis! If there are no arguments, the parentheses are omitted.
<structure> ::= <name> | <name> ( <arguments> )
<arguments> ::= <argument> | <argument> , <arguments>
Arguments may be any legal Prolog values or variables.
A variable is written as a sequence of letters and digits, beginning with a capital letter. The underscore (_) is considered to be a capital letter.
An atom is any sequence of letters and digits, beginning with a lowercase letter. Alternatively, an atom is any sequence of characters, enclosed by single quotes ('); an internal single quote must be doubled. Examples: cat, r124c41, max_value, maxValue, 'max value', 'Don''t go'.
As syntactic sugar, Prolog allows certain infix operators: ',' (comma), ';' (semicolon), ':-' (turnstile), +, -, *, /, =, ==, and many others. These are the same as the operator written as the functor of a structure; for example, 2+2 is the same as '+'(2,2).
Comments begin with the characters /* and end with */. Comments are not restricted to a single line, but may not be nested.
Example: /* This is a comment. */
Unification and instantiation can be performed explicitly with the '=' operator, or implicitly via parameter transmission. Unification is a symmetric operation (X=Y is the same as Y=X), and is not the same as assignment.
Example: mother(john) = mother(john).
2. A variable can be unified with another variable. The two variable names thereafter reference the same variable.
Example: X = Y, X = 2, write(Y). /* Writes the value 2. */
3. A variable can be unified with any Prolog value; this is called instantiating the variable. A variable is fully instantiated if it is unified with a value that does not itself contain variables.
Example: X = foo(bar, [1, 2, 3]). /* X is fully instantiated. */
Example: Pa = husband(Ma). /* Pa is partially instantiated. */
4. Two different values can be unified if there are unifications for the constituent variables which make the values the same.
Example: mother(mary, X) = mother(Y, father(Z)).
[Also results in the unifications mary=Y and X=father(Z)].
5. It is legal to unify a variable with an expression containing itself; however, the resultant value cannot be printed, and must otherwise be handled with extreme care.
Example: X = foo(X, Y).
A variable is written as a sequence of letters and digits, beginning with a capital letter. The underscore (_) is considered to be a capital letter. Examples: X2, Max, This_node, ThisNode.
Prolog variables are similar to "unknowns'' in algebra: Prolog tries to find values for the variables such that the entire clause can succeed. Once a value has been chosen for a variable, it cannot be altered by subsequent code; however, if the remainder of the clause cannot be satisfied, Prolog may backtrack and try another value for that variable.
The anonymous variable consists of a single underscore. Each occurrence of the anonymous variable is considered to be a new, distinct variable (i.e. different occurrences may have different values).
The scope of a variable name is the clause in which it occurs. There are no "global'' variables.
Most Prolog clauses have both a declarative reading and a procedural reading. Whenever possible, the declarative reading is to be preferred.
mother(X, Y) :- parent(X, Y), female(X).
Declarative reading: X is the mother of Y if X is a parent of Y and X is female.
Approximate procedural reading: To show that X is the mother of Y, first show that X is a parent of Y, then show that X is female.
Suppose we have the additional base clauses:
parent(john, bill).
parent(jane, bill).
female(jane).
Now if we inquire:
| ?- mother(M, bill).
the clause of mother/2 will be located, and the unifications X=M, Y=bill will occur. (Parameter transmission is by unification.) Then parent(M, bill) will be attempted, resulting in the unification M=john. Next, female(john) will be attempted, but will fail. Prolog will backtrack to parent(M, bill) and look for another solution for this; it will succeed and unify M=jane. Finally, it will attempt female(jane), and succeed; so the inquiry will succeed, having performed the unification M=jane.
Typically Prolog predicates work regardless of which arguments are instantiated, and may instantiate the others. Thus mother/2 works equally well for the calls mother(jane,C), mother(M,C), and mother(jane,bill) [but the procedural reading is different in each case.] Injudicious use of control predicates, particularly "cut,'', can destroy this property.
[] is the empty list; [a, 2+2, [5]] is the list containing the three elements a, 2+2, and [5]. [Head | Tail] is the list whose first element is Head and whose tail (list of remaining elements) is Tail. [a, X, c | Tail] is the list whose first three elements are a, X, and c, and whose remaining elements are given by the list Tail. Only one term may follow the "|'': [a | X, Y] and [a | X | Y] are syntactic nonsense.
Unification can be performed on lists:
[a, b, c] = [Head | Tail]. /* a = Head, [b, c] = Tail. */
[a, b] = [A, B | T]. /* a = A, b = B, [] = Tail. */
[a, B | C] = [X | Y]. /* a = X, [B | C] = Y. */
In most (but not all) Prolog systems, the list notation is syntactic sugar for the '.' functor, with the equivalence: '.'(Head, Tail) = [Head | Tail].
Two useful predicates are member/2, which succeeds when its first argument is a member of the list that is its second argument, and append/3, which is true when the third argument is the list formed by appending the first two lists. Neither is predefined. Definitions are:
member(A, [A | _]).
member(A, [_ | B]) :- member(A, B).
append([A | B], C, [A | D]) :- append(B, C, D).
append([], A, A).
The operator "=..'', pronounced "univ,'' succeeds when its left argument is a structure and its right argument is the corresponding list [Functor | Args].
Example: mother(M, bill) =.. [mother, M, bill].
A double-quoted character string is syntactic sugar for a list of the ASCII codes for those characters.
Example: "abc" = [97,98,99].
The predicate name/2 succeeds if its first argument is the atom formed from the string that is its second argument.
Example: name(abc, "abc").
How you start Prolog depends on your operating system; try typing prolog at the top-level prompt. Prolog should respond with the "| ?-'' prompt.
To load in predicates from file, use reconsult(FileName) or reconsult([FileName1, FileName2, ...]). If one of the files contains a predicate that already occurs in the database, it replaces the old definition. [The similar predicate consult adds the new clauses after the existing predicates, rather than replacing them.]
To type in predicates directly, use reconsult(user). The prompt will change from "| ?-'' to "|''. Enter predicates as you would on a file. To quit this mode, enter an end-of-file (probably ^D).
"Run'' the program by typing in inquiries at the Prolog prompt. You may call any predicate with any arguments, and you may make multiple calls in one inquiry by separating them with commas. Use a period at the end of each inquiry. There is no "main'' program.
When Prolog does not give you a new prompt after it answers an inquiry, that means there may be other answers. Enter
;<return>
to tell it to get the next answer, or just <return> to tell it you have seen enough.
To begin tracing, use trace; to end tracing, use notrace. To exit Prolog, use halt.
Prolog is a notation for stating logical relations that happens to be executable. It has few control structures, because it is very difficult to assign meanings to control structures. Accordingly, you should try to learn how to write declarative programs. Avoid using the control structures listed below. If you find Prolog frustrating and difficult, you are probably still programming procedurally.
A Prolog predicate consists of multiple clauses. It is useful to think of each clause as coding a separate "case''--first describe what constitutes the case, then describe the result for that case. For example, the absolute value of a number is (1) the negation of the number, if it is negative, or (2) the number itself, if it isn't negative.
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
If a case has subcases, feel free to invent another predicate to deal with the subcases.
Remember that parameter transmission is by unification. You can do a lot of your work right in the parameter list. For example:
second([_, X | _], X). /* 2nd argument is 2nd element of list. */
You can often simplify code by writing parameters that match only the specific case you are interested in. See member and append for examples. (Note: when you must program procedurally, by convention the "result'' is the last argument.)
Recursion is fully supported. In other languages you must always test for the base case first; in Prolog, the base case can (and should) go last, if it is such that the more general clauses will fail--see append. If the predicate is to fail in the base case, it can (and should) be omitted; for example, the base case for member is the unnecessary clause:
member(_, []) :- fail. /* No 1st parameter is a member of [] */
You can't keep a value for future use by "assigning it to a variable.'' If it is temporary, local information, you can pass it around as a parameter; if it is relatively permanent information that should be globally accessible, you can put it in the database (see assert and retract below). Prolog has no functions, so "results'' must be returned by instantiating one or more parameters.
Many predicates can be used as generators, to generate one solution after another until later conditions are met. For example,
member(X, [1, 2, 3, 4, 5]), X > 3.
succeeds and instantiates X to 4. If backed into, it re-instantiates X to 5. (But if you think declaratively, this just says "X is a member of the list [1, 2, 3, 4, 5] that is greater than 3.'')
When one clause fails, the next one is tried. If you want the failure of a clause to cause the failure of the entire predicate, you can use a cut-fail combination:
sqrt(X, RootX) :- X < 0, !, fail.
(more clauses of sqrt should follow)
This is a procedural shortcut that avoids the necessity of having X <= 0 in every clause; it is justified only if the test is complex and there are many clauses.
Arithmetic is performed only upon request. For example, 2+2=4 will fail, because 4 is a number but 2+2 is a structure with functor '+'. Prolog cannot work arithmetic backwards; the following definition of square root ought to work when called with sqrt(25, R), but it doesn't.
sqrt(X, Y) :- X is Y * Y. /* Requires that Y be instantiated. */
Arithmetic is procedural because Prolog isn't smart enough to solve equations, even simple ones. This is a research area.
It is possible to build a so-called fail loop in Prolog. Such a loop has the form generate-process-test; the loop repeats if the test fails. For example, the following will print the elements of a list, one per line:
print_elements(List) :- member(Element, List), write(Element), nl, fail.
However, if the processing is at all complex, it may be difficult to backtrack over it safely. Tail recursion is safer, cleaner, and usually more efficient:
print_elements([Head | Tail]) :- write(Head), nl, print_elements(Tail).
Both of these fail after printing the list. If this is undesirable (and it probably is), a simple idiom is to add another clause whose purpose is to unconditionally succeed after the first clause is done:
print_elements(_).
Prolog has a large number of built-in predicates. The following is a partial list of predicates which should be present in all implementations.
Read one clause from the current input and unify it with X. If there is no further input, X is unified with end_of_file.
Read one printing character from the current input file and unify the ASCII code of that character (an integer) with X.
Read one character from the current input file and unify the ASCII code of that character with X.
Open File as the current input file.
Close the current input file.
Write the single value X to the current output file.
Write X with quotes as needed so it can be read in again.
Write N blanks to the current output file.
Write a newline to the current output file.
Write the character whose ASCII value is X to the current output file.
Open File as the current output file.
Close the current output file.
X or Y. Try X first; if it fails (possibly after being backtracked into), try Y.
If X, then try Y, otherwise fail. Y will not be backtracked into.
If X, then try Y, else try Z. X will not be backtracked into.
(Sometimes written \+X or not(X)) Succeed only when X fails.
Succeed once, but fail when backtracked into.
Always succeed, even when backtracked into.
Never succeed.
(Pronounced "cut".) Acts like true, but cannot be backtracked past, and prevents any other clauses of the predicate it occurs in from being tried.
Return immediately to the top-level Prolog prompt.
Database manipulation predicates
Add X to the database. For syntactic reasons, if X is not a base clause, use assert((X)).
Add X to the database in front of other clauses of this predicate.
Add X to the database after other clauses of this predicate.
Remove X from the database. For syntactic reasons, if X is not a base clause, use retract((X)).
Remove all clauses with functor F and arity A from the database.
Find a clause in the database whose head (left hand side) matches X and whose body (right hand side) matches V. To find a base clause, use true for V.
Save the entire program state on File F (usu. as a binary image).
Replace the program state with the one on File F.
Evaluate E and unify the result with X.
When evaluated, yields the sum of X and Y.
When evaluated, yields the difference of X and Y.
When evaluated, yields the product of X and Y.
When evaluated, yields the quotient of X and Y.
When evaluated, yields the remainder of X divided by Y.
Evaluate X and Y and compare them for equality.
Evaluate X and Y and succeed if they are not equal.
...and similarly for >, <, >=, =<.
Listing and debugging predicates.
Display predicate P. P may be a predicate name, a structure of the form Name/Arity, or a bracked list of the above.
Turn on tracing.
Turn off tracing.
Turn on tracing when predicate P is called. P may be a predicate name, a structure of the form Name/Arity, or a non-bracked list of the above.
Turn off spying for P.
Turn off all spypoints.
Enable spypoints (allow them to initiate tracing.).
Disable spypoints (without removing them).
Control over tracing is very system-dependent, but is probably like this:
Enter key
Single-step to next line of trace.
h
Provide help on tracing commands.
s
(On a CALL) Skip over this call.
l
Leap without tracing to the next spypoint.
n
Turn off tracing.
+
Set a spypoint here.
-
Remove the spypoint here.
Trace terminology: CALL is the initial entry to a predicate; EXIT is a successful return; REDO is when it is backed into for another answer; FAIL is when it finds no more solutions. A sequence of calls may be viewed as forming a chain.
Succeed if X is an atom (an empty list is considered an atom).
Succeed if X is an atom or number.
Succeed if X is a number.
Succeed if X is an integer.
Succeed if X is a real number.
Succeed if X is unbound (a non-instantiated variable).
Succeed if X is bound.
Succeed if X and Y are identical (but do not unify them).
Succeed if X and Y are not identical.
Key takeaway
Prolog is a logic language, not an algorithmic language, and one therefore has to learn to think about programs in a somewhat different way. The terminology is also somewhat different.
The following is a simple Prolog program:
man(socrates).
mortal(X) :- man(X).
The first line can be read, "Socrates is a man.'' It is a base clause, which represents a simple fact.
The second line can be read, "X is mortal if X is a man;'' in other words, "All men are mortal.'' This is a clause, or rule, for determining when its input X is "mortal.'' (The symbol ":-'', sometimes called a turnstile, is pronounced "if''.) We can test the program by asking the question:
| ?- mortal(socrates).
that is, "Is Socrates mortal?'' (The "| ?-'' is the computer's prompt for a question.) Prolog will respond "yes''. Another question we may ask is:
| ?- mortal(X).
That is, "Who (X) is mortal?'' Prolog will respond "X = socrates''.
Java - Basic Operators
Java provides a rich set of operators to manipulate variables. We can divide all the Java operators into the following groups −
Arithmetic operators are used in mathematical expressions in the same way that they are used in algebra. The following table lists the arithmetic operators −
Assume integer variable A holds 10 and variable B holds 20, then −
Show Examples
Operator | Description | Example |
+ (Addition) | Adds values on either side of the operator. | A + B will give 30 |
- (Subtraction) | Subtracts right-hand operand from left-hand operand. | A - B will give -10 |
* (Multiplication) | Multiplies values on either side of the operator. | A * B will give 200 |
/ (Division) | Divides left-hand operand by right-hand operand. | B / A will give 2 |
% (Modulus) | Divides left-hand operand by right-hand operand and returns remainder. | B % A will give 0 |
++ (Increment) | Increases the value of operand by 1. | B++ gives 21 |
-- (Decrement) | Decreases the value of operand by 1. | B-- gives 19 |
There are following relational operators supported by Java language.
Assume variable A holds 10 and variable B holds 20, then −
Show Examples
Operator | Description | Example |
== (equal to) | Checks if the values of two operands are equal or not, if yes then condition becomes true. | (A == B) is not true. |
!= (not equal to) | Checks if the values of two operands are equal or not, if values are not equal then condition becomes true. | (A != B) is true. |
> (greater than) | Checks if the value of left operand is greater than the value of right operand, if yes then condition becomes true. | (A > B) is not true. |
< (less than) | Checks if the value of left operand is less than the value of right operand, if yes then condition becomes true. | (A < B) is true. |
>= (greater than or equal to) | Checks if the value of left operand is greater than or equal to the value of right operand, if yes then condition becomes true. | (A >= B) is not true. |
<= (less than or equal to) | Checks if the value of left operand is less than or equal to the value of right operand, if yes then condition becomes true. | (A <= B) is true. |
Java defines several bitwise operators, which can be applied to the integer types, long, int, short, char, and byte.
Bitwise operator works on bits and performs bit-by-bit operation. Assume if a = 60 and b = 13; now in binary format they will be as follows −
a = 0011 1100
b = 0000 1101
-----------------
a&b = 0000 1100
a|b = 0011 1101
a^b = 0011 0001
~a = 1100 0011
The following table lists the bitwise operators −
Assume integer variable A holds 60 and variable B holds 13 then −
Show Examples
Operator | Description | Example |
& (bitwise and) | Binary AND Operator copies a bit to the result if it exists in both operands. | (A & B) will give 12 which is 0000 1100 |
| (bitwise or) | Binary OR Operator copies a bit if it exists in either operand. | (A | B) will give 61 which is 0011 1101 |
^ (bitwise XOR) | Binary XOR Operator copies the bit if it is set in one operand but not both. | (A ^ B) will give 49 which is 0011 0001 |
~ (bitwise compliment) | Binary Ones Complement Operator is unary and has the effect of 'flipping' bits. | (~A ) will give -61 which is 1100 0011 in 2's complement form due to a signed binary number. |
<< (left shift) | Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand. | A << 2 will give 240 which is 1111 0000 |
>> (right shift) | Binary Right Shift Operator. The left operands value is moved right by the number of bits specified by the right operand. | A >> 2 will give 15 which is 1111 |
>>> (zero fill right shift) | Shift right zero fill operator. The left operands value is moved right by the number of bits specified by the right operand and shifted values are filled up with zeros. | A >>>2 will give 15 which is 0000 1111 |
The following table lists the logical operators −
Assume Boolean variables A holds true and variable B holds false, then −
Show Examples
Operator | Description | Example |
&& (logical and) | Called Logical AND operator. If both the operands are non-zero, then the condition becomes true. | (A && B) is false |
|| (logical or) | Called Logical OR Operator. If any of the two operands are non-zero, then the condition becomes true. | (A || B) is true |
! (logical not) | Called Logical NOT Operator. Use to reverses the logical state of its operand. If a condition is true then Logical NOT operator will make false. | !(A && B) is true |
Following are the assignment operators supported by Java language −
Show Examples
Operator | Description | Example |
= | Simple assignment operator. Assigns values from right side operands to left side operand. | C = A + B will assign value of A + B into C |
+= | Add AND assignment operator. It adds right operand to the left operand and assign the result to left operand. | C += A is equivalent to C = C + A |
-= | Subtract AND assignment operator. It subtracts right operand from the left operand and assign the result to left operand. | C -= A is equivalent to C = C – A |
*= | Multiply AND assignment operator. It multiplies right operand with the left operand and assign the result to left operand. | C *= A is equivalent to C = C * A |
/= | Divide AND assignment operator. It divides left operand with the right operand and assign the result to left operand. | C /= A is equivalent to C = C / A |
%= | Modulus AND assignment operator. It takes modulus using two operands and assign the result to left operand. | C %= A is equivalent to C = C % A |
<<= | Left shift AND assignment operator. | C <<= 2 is same as C = C << 2 |
>>= | Right shift AND assignment operator. | C >>= 2 is same as C = C >> 2 |
&= | Bitwise AND assignment operator. | C &= 2 is same as C = C & 2 |
^= | bitwise exclusive OR and assignment operator. | C ^= 2 is same as C = C ^ 2 |
|= | bitwise inclusive OR and assignment operator. | C |= 2 is same as C = C | 2 |
There are few other operators supported by Java Language.
Conditional operator is also known as the ternary operator. This operator consists of three operands and is used to evaluate Boolean expressions. The goal of the operator is to decide, which value should be assigned to the variable. The operator is written as −
variable x = (expression) ? value if true : value if false
Following is an example −
Example
public class Test {
public static void main(String args[]) {
int a, b;
a = 10;
b = (a == 1) ? 20: 30;
System.out.println( "Value of b is : " + b );
b = (a == 10) ? 20: 30;
System.out.println( "Value of b is : " + b );
}
}
This will produce the following result −
Output
Value of b is : 30
Value of b is : 20
This operator is used only for object reference variables. The operator checks whether the object is of a particular type (class type or interface type). instanceof operator is written as −
( Object reference variable ) instanceof (class/interface type)
If the object referred by the variable on the left side of the operator passes the IS-A check for the class/interface type on the right side, then the result will be true. Following is an example −
Example
public class Test {
public static void main(String args[]) {
String name = "James";
// following will return true since name is type of String
boolean result = name instanceof String;
System.out.println( result );
}
}
This will produce the following result −
Output
true
This operator will still return true, if the object being compared is the assignment compatible with the type on the right. Following is one more example −
Example
class Vehicle {}
public class Car extends Vehicle {
public static void main(String args[]) {
Vehicle a = new Car();
boolean result = a instanceof Car;
System.out.println( result );
}
}
This will produce the following result −
Output
true
Operator precedence determines the grouping of terms in an expression. This affects how an expression is evaluated. Certain operators have higher precedence than others; for example, the multiplication operator has higher precedence than the addition operator −
For example, x = 7 + 3 * 2; here x is assigned 13, not 20 because operator * has higher precedence than +, so it first gets multiplied with 3 * 2 and then adds into 7.
Here, operators with the highest precedence appear at the top of the table, those with the lowest appear at the bottom. Within an expression, higher precedence operators will be evaluated first.
Category | Operator | Associativity |
Postfix | expression++ expression-- | Left to right |
Unary | ++expression –-expression +expression –expression ~ ! | Right to left |
Multiplicative | * / % | Left to right |
Additive | + - | Left to right |
Shift | << >> >>> | Left to right |
Relational | < > <= >= instanceof | Left to right |
Equality | == != | Left to right |
Bitwise AND | & | Left to right |
Bitwise XOR | ^ | Left to right |
Bitwise OR | | | Left to right |
Logical AND | && | Left to right |
Logical OR | || | Left to right |
Conditional | ?: | Right to left |
Assignment | = += -= *= /= %= ^= |= <<= >>= >>>= | Right to left |
Structure and Members of the Java Program
When we are writing any program in any language we need to follow a standard structure for writing the program which is recommended by the language experts. A java program may contain many classes of which only one class will have a main method. Class will contain data members and methods that operate on the data members of the class. To write a Java program, we first need to define classes and then put them together. Generally a standard java program consists of following blocks as shown in below figure.
Explanation:
1. Package is a collection of classes, interfaces and sub packages. In a java program if we are using any pre-defined classes and interfaces then it is the responsibility of the java programmer to import that particular package containing such specific classes and interface. In java by default java.lang.* package is imported by every program.
2. Class is a keyword used for developing user defined data types. Every java program must starts with a prototype of class. The class has been declared public, means all classes can access the class from all packages. Generally, however, we will declare classes in java without specifying a modifier.
3. Class name is the name given to that class. Every class name is treated as one kind of user defined data type.
4. Data Members represents either instance members or static members.
5. Constructor function is called when an object of the class is created. It is a block of code that initializes the newly created object. The constructor simply has the same name as the name of the class name. A constructor does not have a return type. A constructor is called automatically when a new instance of an object is created. In the following code, the constructor bird() prints a message.
When we create the object of the bird class as shown above:
bird b = new bird();
The new keyword here creates the object of class bird and invokes the constructor to initialize this newly created object.
Constructor and method are different because the constructor is used to initialize the object of a class while the method is used to perform a task by implementing java code. Constructors cannot be declared as abstract, final, static and synchronised while methods can be declared. Constructors do not have return types while methods do.
6. User-defined methods represents either instance (or) static and they will be selected depends on the class name and these methods are used for performing the operations either once (or) repeatedly. All the user-defined methods of a class contain logic for a specific problem. These methods are known as Business logic methods.
7. All java program starts its execution with main() method so main() method is known as the backbone of the program. The Java Virtual Machine starts running any java program by executing main() method first.
8. Java’s main() method is not retuning any value so its return type must be void.
9. Also main() method executes only once throughout the life of java program and before the object creation so its nature must be static.
10. The main() method is accessed in all the java programs, its access specifier must be public (universal).
11. Each and every main() method of java must take an array of objects of String class as an argument.
12. The block of statements are set of executable statements written for calling user-defined methods of the class.
13. If we have multiple java files then the naming convention of class file in java is that, whichever class is containing main() method, that class name will be given as the file name with an extension (dot) .java.
Types of Data Members:
Java Class is a collection of data members and functions. Any java program may contain two types of data members. They are;
1. Instance or non-static data members
2. Static or class data members
The following table describes the difference between the two.
Types of Methods:
In java program generally we may define two types of methods apart from constructor. They are;
1. Instance or non –static methods
2. Static or class methods
The following table describes the difference between the two.
The following example named TestGVP.java demonstrates the use of different members of the java class.
// Java code to show structures and // members of Java Program public class classMember {
// Static member static int staticNum = 0;
// Instance member int instanceNum;
/* below constructor increments the static number and initialize instance number */ public classMember(int i) //Constructor method { instanceNum = i; staticNum++; }
/* The show method display the value in the staticNum and instanceNum */ public void show() //instance method { System.out.println("Value of Static Number is:" + staticNum + "\nValue of Instance number is:"+ instanceNum); }
// To find cube public static int cube() //Static method { return staticNum * staticNum * staticNum; }
// Driver code public static void main(String args[]) { classMember gvp1 = new classMember(2); System.out.println("Value after gvp1 object creation: "); gvp1.show();
classMember gvp2 = new classMember(4); System.out.println("Value after gvp2 object creation: "); gvp2.show();
// static method can be accessed by class name int cub=classMember.cube(); System.out.println("Cube of the Static number is: "+ cub); } } |
Output :
Key takeaway
Java provides a rich set of operators to manipulate variables. We can divide all the Java operators into the following groups −
References:
1. T. W. Pratt, M. V. Zelkowitz, "Programming Languages Design and Implementation‖, 4th Ed, PHI, ISBN 81-203-2035-2.
2. Sebesta R., "Concepts of Programming Languages", 4th Edition, Pearson Education, ISBN81-7808-161-X.
3. Herbert Schildt, "The Complete Reference Java", 9th Ed, TMH,ISBN: 978-0-07-180856-9.
4. Dr.R. Nageshwar Rao, "Core Java: An Integrated Approach", Dreamtech Press
5. Deugo, ―Java Gems‖, Cambridge University Press, ISBN 10: 0521648246 ISBN 13: 9780521648240
6. Carl Townsend,” Programming in turbo PROLOG”, Tata-McGraw Hill
7. Ivan Bratko, “Prolog Programming for Artificial Intelligence”, Wesley Publishers Limited
8. Winston P., Klaus B., Horn P., "LISP", 3rd Edition, Pearson Education, 81 - 7808 -155-5
9. Carlo Ghezzi, Mehdi Jazayeri, ―Programming Language Concepts‖,3rd Ed, Wiley Publication ISBN : 978-81-265-1861-6.