0% found this document useful (0 votes)
2 views

UNIT 5

The document provides an overview of functional and logic programming languages, focusing on lambda calculus and the Scheme programming language. It explains the characteristics of mathematical functions, the design of functional programming languages, and introduces key concepts in Scheme such as defining functions, control flow, and list processing. The document also includes examples of Scheme functions and their applications in solving programming problems.

Uploaded by

rsanthi457
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

UNIT 5

The document provides an overview of functional and logic programming languages, focusing on lambda calculus and the Scheme programming language. It explains the characteristics of mathematical functions, the design of functional programming languages, and introduces key concepts in Scheme such as defining functions, control flow, and list processing. The document also includes examples of Scheme functions and their applications in solving programming problems.

Uploaded by

rsanthi457
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

lOMoARcPSD|22190658

PPL UNIT 5 notes - It will be useful

Artificial intelligence (Anna University)

Scan to open on Studocu

Studocu is not sponsored or endorsed by any college or university


Downloaded by Bibsy Adlin Kumari R ([email protected])
lOMoARcPSD|22190658

UNIT 5

FUNCTIONAL AND LOGIC PROGRAMMING LANGUAGES

INTRODUCTION TO LAMBDA CALCULUS:

A mathematical function is a mapping of members of one set, called the domain set, to another
set, called the range set. A function definition specifies the domain and range sets, either
explicitly or implicitly, along with the mapping. The mapping is described by an expression or,
in some cases, by a table.

One of the fundamental characteristics of mathematical functions is that the evaluation order of
their mapping expressions is controlled by recursion and conditional expressions, rather than by
the sequencing and iterative repetition that are common to programs written in the imperative
programming languages.

Another important characteristic of mathematical functions is that because they have no side
effects and cannot depend on any external values, they always map a particular element of the
domain to the same element of the range.

Function definitions are often written as a function name, followed by a list of parameters in
parentheses, followed by the mapping expression. For example,

cube(x) ≡ x * x * x,

where x is a real number. In this definition, the domain and range sets are the real numbers. The
symbol ≡ is used to mean “is defined as.” The parameter x can represent any member of the
domain set, but it is fixed to represent one specific element during evaluation of the function
expression.

cube (2.0) = 2.0 * 2.0 * 2.0 = 8

The parameter x is bound to 2.0 during the evaluation and there are no unbound parameters.
Furthermore, x is a constant (its value cannot be changed) during the evaluation.

A lambda expression specifies the parameters and the mapping of a function. The lambda
expression is the function itself, which is nameless. For example, consider the following lambda
expression:

λ(x)x * x * x

Church defined a formal computation model (a formal system for function definition, function
application, and recursion) using lambda expressions. This is called lambda calculus. Lambda

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

calculus can be either typed or untyped. Untyped lambda calculus serves as the inspiration for
the functional programming language..

Application of the example lambda expression is denoted as in the following example:

(λ(x)x * x * x)(2) which results in the value 8.

Functional form

A higher- order function, or functional form, is one that either takes one or more functions as
parameters or yields a function as its result, or both. One common kind of functional form is
function composition, which has two functional parameters and yields a function whose value is
the first actual parameter function applied to the result of the second. Function composition is
written as an expression, using ° as an operator, as in

h≡f°g
For example, if
f(x) ≡ x + 2
g(x) ≡ 3*x
then h is defined as
h(x) ≡ f ( g(x)), or h(x) ≡ (3*x) x+ 2

Apply-to-all is a functional form that takes a single function as a parameter. If applied to a list of
parameters, apply-to-all applies its functional parameter to each of the values in the list
parameter and collects the results in a list or sequence. Apply-to-all is denoted by a. Consider the
following example:
Let
h(x) ≡ x*x
then
a(h,(2,3,4)) yields (4, 9, 16)

FUNDAMENTALS OF FUNCTIONAL PROGRAMMING LANGUAGES:


The objective of the design of a functional programming language is to mimic mathematical
functions to the greatest extent possible. In an imperative language, an expression is evaluated
and the result is stored in a memory location, which is represented as a variable in a program.
This is the purpose of assignment statements. This necessary attention to memory cells, whose
values represent the state of the program, results in a relatively low-level programming
methodology. A program in an assembly language often must also store the results of partial
evaluations of expressions. For example, to evaluate
(x + y)/(a - b)
the value of (x + y) is computed first. That value must then be stored while (a - b) is evaluated.
The compiler handles the storage of intermediate results of expression evaluations in high-level

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

languages. The storage of intermediate results is still required, but the details are hidden from the
programmer.
A purely functional programming language does not use variables or assignment
statements, thus freeing the programmer from concerns related to the memory cells, or state, of
the program. Without variables, iterative constructs are not possible, for they are controlled by
variables. Repetition must be specified with recursion rather than with iteration. Programs are
function definitions and function application specifications, and executions consist of evaluating
function applications. Without variables, the execution of a purely functional program has no
state in the sense of operational and denotational semantics. The execution of a function always
produces the same result when given the same parameters. This feature is called referential
transparency. It makes the semantics of purely functional languages far simpler than the
semantics of the imperative languages.
A functional language provides a set of primitive functions, a set of functional forms to
construct complex functions from those primitive functions, a function application operation, and
some structure or structures for representing data. These structures are used to represent the
parameters and values computed by functions. If a functional language is well designed, it
requires only a relatively small number of primitive functions.

INTRODUCTION TO SCHEME:
The Scheme language is a language with simple syntax and semantics, Scheme is well
suited to educational applications, such as courses in functional programming, and also to
general introductions to programming.
The Scheme Interpreter:
A Scheme interpreter repeatedly reads an expression typed by the user (in the form of a list),
interprets the expression, and displays the resulting value. This form of interpreter is also used by
Ruby and Python. Expressions are interpreted by the function EVAL. Expressions that are calls
to primitive functions are evaluated in the following way: First, each of the parameter
expressions is evaluated, in no particular order. Then, the primitive function is applied to the
parameter values, and the resulting value is displayed.
Comments in Scheme are any text following a semicolon on any line.
Primitive Numeric Functions:
Scheme includes primitive functions for the basic arithmetic operations. These are +, −, *, and /,
for add, subtract, multiply, and divide. * and + can have zero or more parameters. If * is given no
parameters, it returns 1; if + is given no parameters, it returns 0. + adds all of its parameters
together. * multiplies all its parameters together. / and − can have two or more parameters.
Expression Value
42 42
(* 3 7) 21
(+ 5 7 8) 20
(− 5 6) −1

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

(− 15 7 2) 6
(− 24 (* 4 3)) 12

There are a large number of other numeric functions in Scheme, among them MODULO,
ROUND, MAX, MIN, LOG, SIN, and SQRT. SQRT returns the square root of its numeric
parameter, if the parameter’s value is not negative. If the parameter is negative, SQRT yields a
complex number.

Defining Functions:
In Scheme, a nameless function actually includes the word LAMBDA, and
is called a lambda expression. For example,
(LAMBDA (x) (* x x))
is a nameless function that returns the square of its given numeric parameter. This function can
be applied in the same way that named functions are: by placing it in the beginning of a list that
contains the actual parameters. For example, the following expression yields 49:
((LAMBDA (x) (* x x)) 7)
In this expression, x is called a bound variable within the lambda expression. During the
evaluation of this expression, x is bound to 7. A bound variable never changes in the expression
after being bound to an actual parameter value at the time evaluation of the lambda expression
begins.

The Scheme special form function DEFINE serves two fundamental needs of Scheme
programming: to bind a name to a value and to bind a name to a lambda expression.
The simplest form of DEFINE is one used to bind a name to the value of an expression. This
form is
(DEFINE symbol expression)
For example,
(DEFINE pi 3.14159)
(DEFINE two_pi (* 2 pi))
If these two expressions have been typed to the Scheme interpreter and then pi is typed, the
number 3.14159 will be displayed; when two_pi is typed, 6.28318 will be displayed.
Names in Scheme can consist of letters, digits, and special characters except parentheses; they
are case insensitive and must not begin with a digit.
The second use of the DEFINE function is to bind a lambda expression to a name. In this case,
the lambda expression is abbreviated by removing the word LAMBDA. To bind a name to a
lambda expression, DEFINE takes two lists as parameters. The first parameter is the prototype of
a function call, with the function name followed by the formal parameters, together in a list. The
second list contains an expression to which the name is to be bound. The general form of such a
DEFINE is
(DEFINE (function_name parameters)

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

(expression)
)
The following example call to DEFINE binds the name square to a functional expression that
takes one parameter:
(DEFINE (square number) (* number number))
After the interpreter evaluates this function, it can be used, as in
(square 5)
which displays 25.
Output Functions:
Scheme includes a few simple output functions, but when used with the interactive
interpreter, most output from Scheme programs is the normal output from the interpreter,
displaying the results of applying EVAL to top-level functions.
Numeric Predicate Function:
A predicate function is one that returns a Boolean value.
Function Meaning
= Equal
<> Not equal
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
EVEN? Is it an even number?
ODD? Is it an odd number?
ZERO? Is it zero?

Notice that the names for all predefined predicate functions that have words for names end with
question marks. In Scheme, the two Boolean values are #T and #F (or #t and #f), although the
Scheme predefined predicate functions return the empty list ,(),for false.

Control Flow:
Scheme uses three different constructs for control flow: one similar to the selection construct of
the imperative languages and two based on the evaluation control used in mathematical
functions. The Scheme two-way selector function, named IF, has three parameters: a predicate
expression, a then expression, and an else expression. A call to IF has the form
(IF predicate then_expression else_expression)

(DEFINE (factorial n)
(IF (<= n 1)
1
(* n (factorial (− n 1)))

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

))

List Functions:
One of the more common uses of the Lisp-based programming languages is list
processing. This subsection introduces the Scheme functions for dealing with lists.
Suppose we have a function that has two parameters, an atom and a list, and the purpose of the
function is to determine whether the given atom is in the given list. Neither the atom nor the list
should be evaluated; they are literal data to be processed. To avoid evaluating a parameter, it is
first given as a parameter to the primitive function QUOTE, which simply returns it without
change. The following examples illustrate QUOTE:
(QUOTE A) returns A
(QUOTE (A B C)) returns (A B C)
Calls to QUOTE are usually abbreviated by preceding the expression to be quoted with an
apostrophe (') and leaving out the parentheses around the expression. Thus, instead of (QUOTE
(A B)), '(A B) is used.
The necessity of QUOTE arises because of the fundamental nature of Scheme data and code
have the same
Following are additional examples of the operations of CAR and CDR:
(CAR '(A B C)) returns A
(CAR '((A B) C D)) returns (A B)
(CAR 'A) is an error because A is not a list
(CAR '(A)) returns A
(CAR '()) is an error
(CDR '(A B C)) returns ( C)
(CDR '((A B) C D)) returns (C D)
(CDR 'A) is an error
(CDR '(A)) returns ()
(CDR '()) is an error.
Two machine instructions, also named CAR (contents of the address part of a register) and CDR
(contents of the decrement part of a register), that extracted the associated fields.

As another example of a simple function, consider


(DEFINE (second a_list) (CAR (CDR a_list)))
Once this function is evaluated, it can be used, as in
(second '(A B C))
which returns B.

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

EXAMPLE SCHEME FUNCTIONS:


This section contains several examples of function definitions in Scheme. These programs solve
simple list-processing problems.
Consider the problem of membership of a given atom in a given list that does not include
sublists. Such a list is called a simple list. If the function is named member, it could be used as
follows:
(member 'B '(A B C)) returns #T
(member 'B '(A C D E)) returns #F
Thinking in terms of iteration, the membership problem is simply to compare the given atom and
the individual elements of the given list, one at a time in some order, until either a match is found
or there are no more elements in the list to be compared. A similar process can be accomplished
using recursion. The function can compare the given atom with the CAR of the list. If they
match, the value #T is returned. If they do not match, the CAR of the list should be ignored and
the search continued on the CDR of the list. This process will end if the given atom is found in
the list. If the atom is not in the list, the function will eventually be called (by itself) with a null

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

list as the actual parameter. That event must force the function to return #F. Either the list is
mpty on some call, in which case #F is returned, or a match is found and #T is returned.
Altogether, there are three cases that must be handled in the function: an empty input list, a
match between the atom and the CAR of the list, or a mismatch between the atom and the CAR
of the list, which causes the recursive call.
These three are the three parameters to COND, with the last being the default
case that is triggered by an ELSE predicate. The complete function follows:
(DEFINE (member atm a_list)
(COND
((NULL? a_list) #F)
((EQ? atm (CAR a_list)) #T)
(ELSE (member atm (CDR a_list)))
))
This form is typical of simple Scheme list-processing functions. In such functions, the data in
lists are processed one element at a time. The individual elements are specified with CAR, and
the process is continued using recursion on the CDR of the list.

LET
LET is a function that creates a local scope in which names are temporarily bound to the values
of expressions. It is often used to factor out the common subexpressions from more complicated
expressions.
The following example illustrates the use of LET. It computes the roots of a given quadratic
equation, assuming the roots are real. The mathematical definitions of the real (as opposed to
complex) roots of the quadratic equation ax2 + bx + c are as follows:
root1 = (-b + sqrt(b2 - 4 ac))/2a and
root 2 = (-b - sqrt(b2 - 4 ac))/2 a
(DEFINE (quadratic_roots a b c)
(LET (
(root_part_over_2a
(/ (SQRT (− (* b b) (* 4 a c))) (* 2 a)))
(minus_b_over_2a (/ (− 0 b) (* 2 a)))
)
(LIST (+ minus_b_over_2a root_part_over_2a)
(− minus_b_over_2a root_part_over_2a))
))
This example uses LIST to create the list of the two values that make up the result.

Tail Recursion in Scheme:


function is tail recursive if its recursive call is the last operation in the function. For
example, the member function is tail recursive.

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

(DEFINE (member atm a_list)


(COND
((NULL? a_list) #F)
((EQ? atm (CAR a_list)) #T)
(ELSE (member atm (CDR a_list)))
))
Functional Forms:
This section describes two common mathematical functional forms that are provided by
Scheme: composition and apply-to- all.
Functional Composition:
function composition is a functional form that takes two functions as parameters and
returns a function that first applies the second parameter function to its parameter and then
applies the first parameter function to the return value of the second parameter function. In other
words,
the function h is the composition function of f and g if h(x) = f(g(x)). For example, consider the
following example:
(DEFINE (g x) (* 3 x))
(DEFINE (f x) (+ 2 x))

Now the functional composition of f and g can be written as follows:


(DEFINE (h x) (+ 2 (* 3 x)))
In Scheme, the functional composition function compose can be written
as follows:
(DEFINE (compose f g) (LAMBDA (x)(f (g x))))

An Apply-to-All Functional Form:


The most common functional forms provided in functional programming languages are
variations of mathematical apply- to- all functional forms. The simplest of these is map, which
has two parameters: a function and a list. Map applies the given function to each element of the
given list and returns a list of
the results of these applications. A Scheme definition of map follows:
(DEFINE (map fun a_list)
(COND
((NULL? a_list) '())
(ELSE (CONS (fun (CAR a_list)) (map fun (CDR a_list))))
))
Note the simple form of map, which expresses a complex functional form.As an example of the
use of map, suppose we want all of the elements of a list cubed. We can accomplish this with the
following:

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

(map (LAMBDA (num) (* num num num)) '(3 4 2 6))


This call returns (27 64 8 216).

Programming with ML:


ML is a static-scoped functional programming language, like Scheme.It differs from Lisp
and its dialects, including Scheme, in a number of significant ways. One important difference is
that ML is a strongly typed language, whereas Scheme is essentially typeless. ML has type
declarations for function parameters and the return types of functions, although because of its
type inferencing they are often not used. The type of every variable and expression can be
statically determined. ML, like other functional programming languages, does not have variables
in the sense of the imperative languages. It does have identifiers, which have the appearance of
names of variables in imperative languages. However, these identifiers are best thought of as
names for values.
A table called the evaluation environment stores the names of all implicitly and explicitly
declared identifiers in a program, along with their types. This is like a run-time symbol table.
When an identifier is declared, either implicitly or explicitly, it is placed in the evaluation
environment.
Another important difference between Scheme and ML is that ML uses a syntax that is
more closely related to that of an imperative language than that of Lisp. For example, arithmetic
expressions are written in ML using infix notation.
Function declarations in ML appear in the general form
fun function_name(formal parameters) = expression;
Consider the following ML function declaration:
fun circumf(r) = 3.14159 * r * r;
This specifies a function named circumf that takes a floating-point (real in ML) parameter and
produces a floating- point result. The types are inferred from the type of the literal in the
expression. Likewise, in the function
fun times10(x) = 10 * x;
the parameter and functional value are inferred to be of type int.
Consider the following ML function:
fun square(x) = x * x;
ML determines the type of both the parameter and the return value from the *operator in the
function definition. Because this is an arithmetic operator, the type of the parameter and the
function are assumed to be numeric. In ML, the default numeric type is int. So, it is inferred that
the type of the parameter and the return value of square is int.
If square were called with a floating-point value, as in
square(2.75);
it would cause an error, because ML does not coerce real values to int type. If we wanted square
to accept real parameters, it could be rewritten as
fun square(x) : real = x * x;

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

ML does not allow overloaded functions. Each of the following definitions is also legal:
fun square(x : real) = x * x;
fun square(x) = (x : real) * x;
fun square(x) = x * (x : real);

The ML selection control flow construct is similar to that of the imperative languages. It has the
following general form:
if expression then then_expression else else_expression
The first expression must evaluate to a Boolean value.
For example,
without using this pattern matching, a function to compute factorial could be written as follows:
fun fact(n : int): int = if n <= 1 then 1
else n * fact(n − 1);
Multiple definitions of a function can be written using parameter pattern matching. The different
function definitions that depend on the form of the parameter are separated by an OR symbol (|).
For example, using pattern matching, the factorial function could be written as follows:
fun fact(0) = 1
| fact(1) = 1
| fact(n : int): int = n * fact(n − 1);
If fact is called with the actual parameter 0, the first definition is used; if the actual parameter is
1, the second definition is used; if an int value that is neither 0 nor 1 is sent, the third definition is
used.

In ML, names are bound to values with value declaration statements of the form
val new_name = expression;
For example,
val distance = time * speed;
The val statement binds a name to a value, but the name cannot be later rebound to a new value.
Actually, if you do rebind a name with a second val statement, it causes a new entry in the
evaluation environment that is not related to the previous version of the name. In fact, after the
new binding, the old evaluation environment entry (for the previous binding) is no longer visible.
Also, the type of the new binding need not be the same as that of the previous binding. val
statements do not have side effects. They simply add a name to the current evaluation
environment and bind it to a value.
The normal use of val is in a let expression.
Consider the following
example:
let val radius = 2.7
val pi = 3.14159

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

int pi * radius * radius


end;
these are a filtering function for lists, filter, which takes a predicate function as its parameter.
The predicate function is often given as a lambda expression, which in ML is defined exactly
like a function, except with the fn reserved word, instead of fun, and of course the lambda
expression is nameless. filter returns a function that takes a list as a parameter. It tests each
element of the list with the predicate.

Each element on which the predicate returns true is added to a new list, which is the return value
of the function. Consider the following use of filter:
filter(fn(x) => x < 100, [25, 1, 50, 711, 100, 150, 27, 161, 3]);

This application would return


[25, 1, 50, 27, 3].
The map function takes a single parameter, which is a function. The resulting function takes a list
as a parameter. It applies its function to each element of the list and returns a list of the results of
those applications. Consider the following code:
fun cube x = x * x * x;
val cubeList = map cube;
val newList = cubeList [1, 3, 5];
After execution, the value of newList is [1, 27, 125]. This could be done more simply by
defining the cube function as a lambda expression, as in the following:
val newList = map (fn x => x * x * x, [1, 3, 5]);

ML has a binary operator for composing two functions, o (a lowercase “oh”). For example, to
build a function h that first applies function f and then applies function g to the returned value
from f, we could use the following:
val h = g o f;
The process of currying replaces a function with more than one parameter with a function with
one parameter that returns a function that takes the other parameters of the initial function.ML
functions that take more than one parameter can be defined in curried form by leaving out the
commas between the parameters (and the delimiting parentheses). For example, we could have
the following:
fun add a b = a + b;
Although this appears to define a function with two parameters, it actually defines one with just
one parameter. The add function takes an integer parameter (a) and returns a function that also
takes an integer parameter (b). A call to this function also excludes the commas between the
parameters, as in the following:
add 3 5;
This call to add returns 8, as expected.

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

Curried functions are interesting and useful because new functions can be constructed from them
by partial evaluation. Partial evaluation means that the function is evaluated with actual
parameters for one or more of the leftmost formal parameters. For example, we could define a
new function as follows:
fun add5 x = add 5 x;
The add5 function takes the actual parameter 5 and evaluates the add function with 5 as the value
of its first formal parameter. It returns a function that adds 5 to its single parameter, as in the
following:
val num = add5 10;
The value of num is now 15.
We could create any number of new functions from the curried function add to add any specific
number to a given parameter.

INTRODUCTION TO LOGIC AND LOGIC PROGRAMMING:


Languages used for logic programming are called declarative languages, because programs
written in them consist of declarations rather than assignments and control flow statements.
One of the essential characteristics of logic programming languages is their semantics, which is
called declarative semantics. The basic concept of this semantics is that there is a simple way to
determine the meaning of each statement, and it does not depend on how the statement might be
used to solve a problem. Declarative semantics is considerably simpler than the semantics of the
imperative languages. For example, the meaning of a given proposition in a logic programming
language can be concisely determined from the statement itself.
Programming in both imperative and functional languages is primarily procedural, which
means that the programmer knows what is to be accomplished by a program and instructs the
computer on exactly how the computation is to be done. In other words, the computer is treated
as a simple device that obeys orders.
Programming in a logic programming language is nonprocedural. Programs in such
languages do not state exactly how a result is to be computed but rather describe the form of the
result. The difference is that we assume the computer system can somehow determine how the
result is to be computed. What is needed to provide this capability for logic programming
languages is a concise means of supplying the computer with both the relevant information and a
method of inference for computing desired results. Predicate calculus supplies the basic form of
communication to the computer.
Sorting is commonly used to illustrate the difference between procedural and
nonprocedural systems. In a language like Java, sorting is done by explaining in a Java program
all of the details of some sorting algorithm to a computer that has a Java compiler. The computer,
after translating the Java program into machine code or some interpretive intermediate code,
follows the instructions and produces the sorted list. In a nonprocedural language, it is necessary
only to describe the characteristics of the sorted list: It is some permutation of the given list such
that for each pair of adjacent elements, a given relationship holds between the two elements. To

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

state this formally, suppose the list to be sorted is in an array named list that has a subscript range
1 . . . n. The concept of sorting the elements of the given list, named old_list, and placing them in
a separate array, named new_list, can then be expressed as follows:
sort(old_list, new_list) ⊂ permute(old_list, new_list) ∩ sorted(new_list)
sorted(list) ⊂ ∀j such that 11 ≤j < n, list(j)≤ list(j + 1)
where permute is a predicate that returns true if its second parameter array is a permutation of its
first parameter array.

PROGRAMMING WITH PROLOG:


Terms: Prolog programs consist of collections of statements. There are only a few kinds
of statements in Prolog, but they can be complex. All Prolog statement, as well as Prolog data,
are constructed from terms.
A Prolog term is a constant, a variable, or a structure. A constant is either an atom or an integer.
An atom is either a string of letters, digits, and underscores that begins with a lowercase letter or
a string of any printable ASCII characters delimited by apostrophes.
A variable is any string of letters, digits, and underscores that begins with an uppercase
letter or an underscore ( _ ). Variables are not bound to types by declarations. The binding of a
value, and thus a type, to a variable is called an instantiation. A variable that has not been
assigned a value is called uninstantiated.
Fact Statements:
Prolog has two basic statement forms; these correspond to the headless and headed Horn
clauses of predicate calculus. The simplest form of headless Horn clause in Prolog is a single
structure, which is interpreted as an unconditional assertion, or fact. Logically, facts are simply
propositions that are assumed to be true. The following examples illustrate the kinds of facts one
can have in a Prolog program. Notice that every Prolog statement is terminated by a period.
female(shelley).
male(bill).
female(mary).
male(jake).
father(bill, jake).
father(bill, shelley).
mother(mary, jake).
mother(mary, shelley).
These simple structures state certain facts about jake, shelley, bill, and mary. For example, the
first states that shelley is a female. The most common and straightforward meaning is bill is the
father of jake.
Rule Statement:
This form can be related to a known theorem in mathematics from which a conclusion
can be drawn if the set of given conditions is satisfied. The right side is the antecedent, or if part,

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

and the left side is the consequent, or then part. If the antecedent of a Prolog statement is true,
then the consequent of the statement must also be true.
Conjunctions contain multiple terms that are separated by logical AND operations. In
Prolog, the AND operation is implied.
The general form of the Prolog headed Horn clause statement is
consequence :- antecedent_expression.
It is read as follows: “consequence can be concluded if the antecedent expression is true
or can be made to be true by some instantiation of its variables.”
For example,
ancestor(mary, shelley) :- mother(mary, shelley).
states that if mary is the mother of shelley, then mary is an ancestor of shelley.
Goal Statements:
These statements are the basis for the theorem-proving model. The theorem is in the form
of a proposition that we want the system to either prove or disprove. In Prolog, these
propositions are called goals, or queries. For example, we could have
man(fred).
to which the system will respond either yes or no. The answer yes means that the system has
proved the goal was true. The answer no means that either the goal was determined to be false or
the system was simply unable to prove it.

The Inferencing Process of Prolog:


Queries are called goals. When a goal is a compound proposition, each of the
facts (structures) is called a subgoal. To prove that a goal is true, the inferencing process must
find a chain of inference rules and/or facts in the database that connect the goal to one or more
facts in the database. For example, if Q is the goal, then either Q must be found as a fact in the
database or the inferencing process must find a fact P1 and a sequence of propositions P2, P3, c ,
Pn such that
P2 :- P1
P3 :- P2
...
Q :- Pn
Because the process of proving a subgoal is done through a proposition-matching process, it is
sometimes called matching. In some cases, proving a subgoal is called satisfying that subgoal.
Consider the following query:
man(bob).
father(bob).
man(X) :- father(X).
Prolog would be required to find these two statements and use them to infer the truth of the goal.
There are two opposite approaches to attempting to match a given goal to a fact in the database.
The system can begin with the facts and rules of the database and attempt to find a sequence of

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

matches that lead to the goal. This approach is called bottom-up resolution, or forward chaining.
The alternative is to begin with the goal and attempt to find a sequence of matching propositions
that lead to some set of original facts in the database. This approach is called top-down
resolution, or backward chaining.
The following example illustrates the difference between forward and backward chaining.
Consider the query:
man(bob).
Assume the database contains
father(bob).
man(X) :- father(X).
Forward chaining would search for and find the first proposition. The goal is then inferred by
matching the first proposition with the right side of the second rule (father(X)) through
instantiation of X to bob and then matching the left side of the second proposition to the goal.
Backward chaining would first match the goal with the left side of the second proposition
(man(X)) through the instantiation of X to bob. As its last step, it would match the right side of
the second proposition (now father(bob)) with the first proposition.
The next design question arises whenever the goal has more than one structure, as in our
example. The question then is whether the solution search is done depth first or breadth first. A
depth-first search finds a complete sequence of propositions—a proof—for the first subgoal
before working on the others. A breadth-first search works on all subgoals of a given goal in
parallel.

When a goal with multiple subgoals is being processed and the system fails to show the truth of
one of the subgoals, the system abandons the subgoal it cannot prove. It then reconsiders the
previous subgoal, if there is one, and attempts to find an alternative solution to it. This backing
up in the goal to the reconsideration of a previously proven subgoal is called backtracking. A
new solution is found by beginning the search where the previous search for that subgoal
stopped.

Simple Arithmetic:
Prolog supports integer variables and integer arithmetic. Originally, the arithmetic operators
were functors, so that the sum of 7 and the variable X was formed with +(7, X) Prolog now
allows a more abbreviated syntax for arithmetic with the is operator. This operator takes an
arithmetic expression as its right operand and a variable as its left operand. All variables in the
expression must already be instantiated, but the left-side variable cannot be previously
instantiated. For example, in A is B / 17 + C. if B and C are instantiated but A is not, then this
clause will cause A to be instantiated with the value of the expression.
This basic information can be coded as facts, and the relationship
between speed, time, and distance can be written as a rule, as in the following:
speed(ford, 100).

Downloaded by Bibsy Adlin Kumari R ([email protected])


lOMoARcPSD|22190658

speed(chevy, 105).
speed(dodge, 95).
speed(volvo, 80).
time(ford, 20).
time(chevy, 21).
time(dodge, 24).
time(volvo, 24).
distance(X, Y) :- speed(X, Speed),time(X, Time),
Y is Speed * Time.
Now, queries can request the distance traveled by a particular car. For example, the query
distance(chevy, Chevy_Distance).
instantiates Chevy_Distance with the value 2205.

MULTI-PARADIGM LANGUAGES:
A programming language that supports both procedural and object-oriented programming
concepts. C++ is one of the multi paradigm language because it has the concepts of
programming language but added the object oriented concepts also.

Downloaded by Bibsy Adlin Kumari R ([email protected])

You might also like