Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
362 views

Principles of Programming Languages UNIT I

This document discusses principles of programming languages, including the importance of studying programming languages, history of programming languages, impact of programming paradigms, role of programming languages, and programming environments. It also covers fundamentals like the operation of a computer, virtual computers, binding times, and the four main programming paradigms of procedural, object-oriented, functional, and logic/rule-based.

Uploaded by

nisha
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
362 views

Principles of Programming Languages UNIT I

This document discusses principles of programming languages, including the importance of studying programming languages, history of programming languages, impact of programming paradigms, role of programming languages, and programming environments. It also covers fundamentals like the operation of a computer, virtual computers, binding times, and the four main programming paradigms of procedural, object-oriented, functional, and logic/rule-based.

Uploaded by

nisha
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 91

Principles of Programming Languages [210255]

SE Computer Engineering

UNIT-I
Fundamentals of Programming
Unit I Contents (06 Hours)
• Importance of Studying Programming Languages,
History of Programming Languages, Impact of
Programming Paradigms, Role of Programming
Languages, Programming Environments. Impact of
Machine Architectures: The operation of a computer,
Virtual Computers and Binding Times.
• Programming paradigms- Introduction to
programming paradigms, Introduction to four main
Programming paradigms- procedural, object
oriented, functional, and logic and rule based.
Text Books
T1. T. W. Pratt, M. V. Zelkowitz, "Programming
Languages Design and Implementation‖, 4th Ed,
PHI, ISBN 81-203-2035-2.

T2. Sebesta R., "Concepts of Programming


Languages", 4th Edition, Pearson Education,
ISBN- 81-7808-161-X.
Importance of Studying Programming Languages (T1, T2 Chapter 1)

• Increased capacity to express ideas.


• Improved background for choosing
appropriate languages.
• Increased ability to learn new languages.
• Better understanding of the significance of
implementation.
• Better use of languages that are already known
• Overall advancement of computing.
History of Programming Languages
T1 Chapter 1
Very low-level languages
• Those are machine languages and assembly
languages, machine-dependent coding
systems. They were initially fully binary, and
then symbolic.
• There is one native machine language, and
usually one assembly language per processor
model.
• Upward compatibility .
Algol 60
• It was the first to have block structure,
recursion, and a formal definition.
• It is not used now, but it is the ancestor of
most contemporary languages.
• As far as design goes, Algol 60 was without
doubt the most important innovation in the
history of programming languages
Cobol
• Business-oriented computations
– very strict program organization
– poor control structures
– elaborate data structures, record type introduced
for the first time.

Used to be very popular in business and


government, much less at universities.
PL/I
• A combination of features believed (at the
time) best in Fortran, Algol 60, Cobol.
– the first language designed to be completely
general, good for all possible applications
(what applications did not exist then?)
– actively promoted by IBM
– not used much today.
• An interesting feature introduced in PL/I:
event handling.
Basic
• The first in history language of personal
computing.
• The first programming language for many
programmers: designed to be easy to learn.
• Very simple, limited, though still general-
purpose.
Simula 67
• An extension of Algol 60 designed for
simulation of concurrent processes.
• Introduced the central concepts of object
orientation: classes and encapsulation.
• Predecessor of Smalltalk and C++.
• Now unused.
Algol 68
• A very elegant design, unmatched till today.
• Full orthogonality.
• Extremely difficult to implement.
• A very clever formal description, unfortunately
hard to understand for most potential users.
• Completely unused.
Pascal
• A conceptually simplified and cleaned-up
successor of Algol 60.
• A great language for teaching structured
programming.
• An excellent first language to learn: teaches good
programming habits.
• Its later extensions (for example, Delphi) are full-
fledged systems programming packages, as
powerful as any Java kit.
Modula-2
• A better, conceptually uniform successor of
Pascal.
• Mechanisms to program concurrency (many
processes running in parallel).
• Not used as much as it deserves.
• Its successors, Modula-3 and Oberon, are even
more conceptually appealing, practically useful—
and almost not used at all. (They lost the
popularity contest with C++.)
Ada
• The result of an elaborate, multi-stage design
process, and a more successful attempt at
generality than PL/I.
• Completely standard: there can be no dialects
(like Java, except that Microsoft...).
• There are, however, two standards: Ada 83 (the
original), and Ada 95.
• Ada has been designed to support concurrency
in a very neat, systematic way.
C
• The implementation language of Unix.
• A great tool for systems programming and a
software development language on personal
computers.
• Once fashionable, still in use, but usually
superseded by C++.
• Dangerous if not used properly:
not recommended to novice programmers.
• Relatively low-level.
Lisp
• One of the earliest programming languages.
• Based on the concept of computing by evaluating
functions. Very good for symbolic computing.
• For years, the only language for Artificial Intelligence
work. (Prolog is 12 years younger.)
• Many dialects, two standards (Scheme, Common Lisp).
• Nice programming environments.
• Lisp's successors are very elegant (Miranda, ML,
Haskell) but not nearly as widely used.
Prolog
• A very high-level programming language.
• Declarative, based on a subset of logic, with proofs
interpreted as computation.
• Very powerful:
– Non-deterministic (built-in backtracking).
– Elaborate, flexible pattern matching.
– Associative memory.
– Pattern-directed procedure invocation.
• In skilled hands, it is a very strong tool.
Smalltalk
• It is the purest object-oriented language ever
designed (till now), cleaner than Java, much
cleaner than C++.
• Comes complete with a graphical interface
and an integrated programming environment.
• In skilled hands, a powerful tool.
C++
• An object-oriented extension of the imperative
language C.
• This is a hybrid design, with object orientation
added to a completely different base
language.
• Complicated syntax, difficult semantics.
• Very fashionable, very much in demand.
Java
• A neat, cleaned up, sized-down reworking of
C++.
• Full object orientation (though not as
consistent as Smalltalk)
• Designed for Internet programming, but
general-purpose.
• It is said (not quite correctly) to be slow.
Scripting languages
• Text processing:
– Perl
– Python
• Web programming
– JavaScript
– PHP
Languages that merge
programming paradigms
• Object-oriented extensions: not only C++, but
dialects of Lisp (CLOS) or of Prolog
(XPCE/Prolog, Prolog++).
• Logic programming combined with functional
programming (very clever, but only
experimental).
• Most languages are sequential: one processor,
one process. Ada is a language designed to
support concurrency: many processes running
in parallel.
Impact of Programming Paradigms
T1 Chapter 1
Programming Paradigm
•A programming paradigm is a fundamental style of computer programming.

•Compare with a software development methodology, which is a style of


solving specific software engineering problems.

•Different methodologies are more suitable for solving certain kinds of


problems or applications domains.

•Same for programming languages and paradigms.

•Programming paradigms differ in:


•the concepts and abstractions used to represent the elements of a program (such as objects, functions, variables, constraints, etc.)
•the steps that compose a computation (assignation, evaluation, data flow, control flow, etc.).
Programming Paradigm
• Some languages are designed to support one particular paradigm
– Smalltalk supports object-oriented programming
– Haskell supports functional programming

• Other programming languages support multiple paradigms


– Object Pascal, C++, C#, Visual Basic, Common Lisp, Scheme, Perl, Python, Ruby,
Oz and F#.

• The design goal of multi-paradigm languages is to allow programmers to


use the best tool for a job, admitting that no one paradigm solves all
problems in the easiest or most efficient way.
Impact of Programming Paradigms
T1 Chapter 1

• Problem Solving
• What is Programming Language
• Software Design
Role of Programming Languages
T1 Chapter 1
Role of Programming Languages
T1 Chapter 1

• A programming language allows people to create


programs that tell machines (Computers) what to
do.
• A programming language is a tool for developing
executable models for a class of problem domains.
• What makes a Good Language
• Language Paradigms
• Language Standardization
• Internationalization
Programming Environments
T1 Chapter 1

• Effects on Language Design


• Environment Framework
• Job Control and Process Languages
Impact of Machine Architectures
T1 Chapter 1
The operation of a computer
(T1 Chapter 1)

• Computer Hardware
• Firmware Computer
• Translators and Firmware Architectures
Virtual Computers and Binding Times

• Virtual Computers and Language


Implementations
• Hierarchies of Virtual Machines
• Binding and Binding Time
What is a computer ?
• A computer is a programmable machine that
receives input, stores and manipulates data or
information, and provides output in a useful
format.
• While a computer can, in theory, be made out of
almost anything, and mechanical examples of
computers have existed through much of recorded
human history, the first electronic computers were
developed in the mid-20th century (1940–1945).
Virtual Computer
• The Virtual Computer is completely
reconfigurable in every respect.
• Computing machines based on
reconfigurable logic are hyper-scalable.
Binding time
• Binding time is the moment in the program's
life cycle when this association occurs.
• Many properties of a programming language
are defined during its creation.
• For instance, the meaning of key words such
as while or for in C, or the size of the integer
data type in Java, are properties defined at
language design time.
Programming paradigms (T2)
Introduction to Programming Paradigm
• A programming paradigm can be understood as an abstraction of a
computer system, for example the von Neumann model used in
traditional sequential computers.
• For parallel computing, there are many possible models typically
reflecting different ways processors can be interconnected to
communicate and share information.
• In object-oriented programming, programmers can think of a program
as a collection of interacting objects, while in functional programming
a program can be thought of as a sequence of stateless function
evaluations.
• In process-oriented programming, programmers think about
applications as sets of concurrent processes acting upon shared data
structures.
Processing Paradigms
• A programming paradigm can be understood as an abstraction of a
computer system, who is based on a certain processing model or paradigm.

• Nowadays, the prevalent computer processing model used is the von


Neumann model, invented by John von Neumann in 1945, influenced by
Alan Turing’s “Turing machine”.
• Data and program are residing in the memory.
• Control unit coordinates the components sequentially following the program’s
instructions.
• Arithmetic Logical Unit performs the calculations.
• Input/output provide interfaces to the exterior.

• The program and its data are what is abstracted in a programming language
and translated into machine code by the compiler/interpreter.
Introduction to four main Programming
paradigms
Introduction to four main Programming
paradigms
• Procedural
• Object oriented
• Functional
• Logic and rule based
Low level
• Initially, computers were hard-wired or soft-wired
and then later programmed using binary code that
represented control sequences fed to the computer
CPU.

• This was difficult and error-prone. Programs written


in binary are said to be written in machine code,
which is a very low-level programming paradigm.
Hard-wired, soft-wired, and binary programming are
considered first generation languages.
Low level
• To make programming easier, assembly languages were developed.

• These replaced machine code functions with mnemonics and memory addresses
with symbolic labels.

• Assembly language programming is considered a low-level paradigm although it is


a 'second generation' paradigm.

• Assembly languages of the 1960s eventually supported libraries and quite


sophisticated conditional macro generation and pre-processing capabilities.

• They also supported modular programming features such as subroutines,


external variables and common sections (globals), enabling significant code re-
use and isolation from hardware specifics via use of logical operators.
Procedural programming
Procedural programming
• Often thought as a synonym for imperative programming.
• Specifying the steps the program must take to reach the desired state.
• Based upon the concept of the procedure call.
• Procedures, also known as routines, subroutines, methods, or functions
that contain a series of computational steps to be carried out.
• Any given procedure might be called at any point during a program's
execution, including by other procedures or itself.
• A procedural programming language provides a programmer a means to
define precisely each step in the performance of a task. The programmer
knows what is to be accomplished and provides through the language step-
by-step instructions on how the task is to be done.
• Using a procedural language, the programmer specifies language
statements to perform a sequence of algorithmic steps.
Procedural programming
• Possible benefits:
– Often a better choice than simple sequential or unstructured programming in many
situations which involve moderate complexity or require significant ease of
maintainability.
– The ability to re-use the same code at different places in the program without copying
it.
– An easier way to keep track of program flow than a collection of "GOTO" or "JUMP"
statements (which can turn a large, complicated program into spaghetti code).
– The ability to be strongly modular or structured.

• The main benefit of procedural programming over first- and


second-generation languages is that it allows for modularity, which
is generally desirable, especially in large, complicated programs.

• Modularity was one of the earliest abstraction features identified


as desirable for a programming language.
Procedural programming
• Scoping is another abstraction technique that helps to keep
procedures strongly modular.

• It prevents a procedure from accessing the variables of other


procedures (and vice-versa), including previous instances of itself such
as in recursion.

• Procedures are convenient for making pieces of code written by


different people or different groups, including through programming
libraries.
– specify a simple interface
– self-contained information and algorithmics
– reusable piece of code
Procedural programming
• The focus of procedural programming is to break down a
programming task into a collection of variables, data
structures, and subroutines, whereas in object-oriented
programming it is to break down a programming task into
objects with each "object" encapsulating its own data and
methods (subroutines).

• The most important distinction is whereas procedural


programming uses procedures to operate on data structures,
object-oriented programming bundles the two together so
an "object" operates on its "own" data structure.
Procedural programming
• The earliest imperative languages were the machine languages of the original
computers. In these languages, instructions were very simple, which made hardware
implementation easier, but hindered the creation of complex programs.
• FORTRAN (1954) was the first major programming language to remove through
abstraction the obstacles presented by machine code in the creation of complex
programs.
• FORTRAN was a compiled language that allowed named variables, complex
expressions, subprograms, and many other features now common in imperative
languages.
• In the late 1950s and 1960s, ALGOL was developed in order to allow mathematical
algorithms to be more easily expressed.
• In the 1970s, Pascal was developed by Niklaus Wirth, and C was created by Dennis
Ritchie.
• For the needs of the United States Department of Defense, Jean Ichbiah and a team
at Honeywell began designing Ada in 1978.
Object-oriented programming programming
paradigms
Object-oriented programming
• Object-oriented programming (OOP) is a programming paradigm that uses
"objects" – data structures encapsulating data fields and procedures together
with their interactions – to design applications and computer programs.

• Associated programming techniques may include features such as data


abstraction, encapsulation, modularity, polymorphism, and inheritance.

• Though it was invented with the creation of the Simula language in 1965, and
further developed in Smalltalk in the 1970s, it was not commonly used in
mainstream software application development until the early 1990s.

• Many modern programming languages now support OOP.


OOP concepts: class
• A class defines the abstract characteristics of a thing (object), including that thing's
characteristics (its attributes, fields or properties) and the thing's behaviors (the
operations it can do, or methods, operations or functionalities).

• One might say that a class is a blueprint or factory that describes the nature of
something.

• Classes provide modularity and structure in an object-oriented computer program.

• A class should typically be recognizable to a non-programmer familiar with the problem


domain, meaning that the characteristics of the class should make sense in context.
Also, the code for a class should be relatively self-contained (generally using
encapsulation).

• Collectively, the properties and methods defined by a class are called its members.
OOP concepts: object
– An object is an individual of a class created at run-time trough object instantiation
from a class.

– The set of values of the attributes of a particular object forms its state. The object
consists of the state and the behavior that's defined in the object's class.

– The object is instantiated by implicitly calling its constructor, which is one of its
member functions responsible for the creation of instances of that class.
OOP concepts: attributes
• An attribute, also called data member or member variable, is the data encapsulated within a class or
object.

• In the case of a regular field (also called instance variable), for each instance of the object there is an
instance variable.

• A static field (also called class variable) is one variable, which is shared by all instances.

• Attributes are an object’s variables that, upon being given values at instantiation (using a constructor)
and further execution, will represent the state of the object.

• A class is in fact a data structure that may contain different fields, which is defined to contain the
procedures that act upon it. As such, it represents an abstract data type.

• In pure object-oriented programming, the attributes of an object are local and cannot be seen from the
outside. In many object-oriented programming languages, however, the attributes may be accessible,
though it is generally considered bad design to make data members of a class as externally visible.
OOP concepts: method
• A method is a subroutine that is exclusively associated either with a class (in
which case it is called a class method or a static method) or with an object (in
which case it is an instance method).

• Like a subroutine in procedural programming languages, a method usually


consists of a sequence of programming statements to perform an action, a set
of input parameters to customize those actions, and possibly an output value
(called the return value).

• Methods provide a mechanism for accessing and manipulating the


encapsulated state of an object.

• Encapsulating methods inside of objects is what distinguishes object-oriented


programming from procedural programming.
OOP concepts: inheritance
• Inheritance is a way to compartmentalize and reuse code by creating
collections of attributes and behaviors (classes) which can be based on
previously created classes.
• The new classes, known as subclasses (or derived classes), inherit attributes
and behavior of the pre-existing classes, which are referred to as super
classes (or ancestor classes). The inheritance relationships of classes gives
rise to a hierarchy.
• Multiple inheritance can be defined whereas a class can inherit from more
than one superclass. This leads to a much more complicated definition and
implementation, as a single class can then inherit from two classes that have
members bearing the same names, but yet have different meanings.
• Abstract inheritance can be defined whereas abstract classes can declare
member functions that have no definitions and are expected to be defined in
all of its subclasses.
OOP concepts: encapsulation and
information hiding
• Encapsulation refers to the bundling of data members and member
functions inside of a common “box”, thus creating the notion that an object
contains its state as well as its functionalities
• Information hiding refers to the notion of choosing to either expose or
hide some of the members of a class.
• These two concepts are often misidentified. Encapsulation is often
understood as including the notion of information hiding.
• Encapsulation is achieved by specifying which classes may use the
members of an object. The result is that each object exposes to any class a
certain interface — those members accessible to that class.
• The reason for encapsulation is to prevent clients of an interface from
depending on those parts of the implementation that are likely to change
in the future, thereby allowing those changes to be made more easily, that
is, without changes to clients.
• It also aims at preventing unauthorized objects to change the state of an
object.
OOP concepts: polymorphism
• Polymorphism is the ability of objects belonging to different types to respond
to method, field, or property calls of the same name, each one according to an
appropriate type-specific behavior.
• The programmer (and the program) does not have to know the exact type of
the object at compile time. The exact behavior is determined at run-time using
a run-time system behavior known as dynamic binding.
• Such polymorphism allows the programmer to treat derived class members
just like their parent class' members.
• The different objects involved only need to present a compatible interface to
the clients. That is, there must be public or internal methods, fields, events,
and properties with the same name and the same parameter sets in all the
superclasses, subclasses and interfaces.
• In principle, the object types may be unrelated, but since they share a common
interface, they are often implemented as subclasses of the same superclass.
Functional Programming programming
paradigm
Functional Programming Paradigm
• Functional programming is a programming paradigm that treats
computation as the evaluation of mathematical functions and
avoids state changes and mutable data.

• It emphasizes the application of functions, in contrast to the


imperative programming style, which emphasizes changes in state.

• Programs written using the functional programming paradigm are


much more easily representable using mathematical concepts, and
thus it is much more easy to mathematically reason about
functional programs than it is to reason about programs written in
any other paradigm.
Functional Programming
• Functional programming has its roots in the lambda calculus, a formal
system developed in the 1930s to investigate function definition, function
application, and recursion. Many functional programming languages can
be viewed as elaborations on the lambda calculus.

• LISP was the first operational functional programming language.

• Up to this day, functional programming has not been very popular except
for a restricted number of application areas, such as artificial intelligence.

• John Backus presented the FP programming language in his 1977 Turing


Award lecture "Can Programming Be Liberated From the von Neumann
Style? A Functional Style and its Algebra of Programs".
Functional Programming
• Functional programming languages, especially purely functional ones, have largely
been emphasized in academia rather than in commercial software development.

• However, prominent functional programming languages such as Scheme, Erlang,


Objective Caml, and Haskell have been used in industrial and commercial
applications by a wide variety of organizations.

• Functional programming also finds use in industry through domain-specific


programming languages like R (statistics), Mathematica (symbolic math), J and K
(financial analysis), F# in Microsoft .NET and XSLT (XML).

• Widespread declarative domain-specific languages like SQL and Lex/Yacc, use some
elements of functional programming, especially in eschewing mutable values.
Spreadsheets can also be viewed as functional programming languages.
Functional Programming
• In practice, the difference between a mathematical function and the notion of a
"function" used in imperative programming is that imperative functions can have
side effects, changing the value of already calculated variables.

• Because of this they lack referential transparency, i.e. the same language expression
can result in different values at different times depending on the state of the
executing program.

• Conversely, in functional code, the output value of a function depends only on the
arguments that are input to the function, so calling a function f twice with the same
value for an argument x will produce the same result f(x) both times.

• Eliminating side-effects can make it much easier to understand and predict the
behavior of a program, which is one of the key motivations for the development of
functional programming.
Functional Programming: Higher-Order
Functions
• Most functional programming languages use higher-order functions, which are functions
that can either take other functions as arguments or return functions as results.

• The differential operator d/dx that produces the derivative of a function f is an example of
this in calculus.

• Higher-order functions are closely related to functions as first-class citizen, in that higher-
order functions and first-class functions both allow functions as arguments and results of
other functions.

• The distinction between the two is subtle: "higher-order" describes a mathematical


concept of functions that operate on other functions, while "first-class" is a computer
science term that describes programming language entities that have no restriction on
their use (thus first-class functions can appear anywhere in the program that other first-
class entities like numbers can, including as arguments to other functions and as their
return values).
Functional Programming:
Pure Functions
• If the entire language does not allow side-effects, then any evaluation strategy can be
used; this gives the compiler freedom to reorder or combine the evaluation of
expressions in a program. This allows for much more freedom in optimizing the
evaluation.

• The notion of pure function is central to code optimization in compilers, even for
procedural programming languages.

• While most compilers for imperative programming languages can detect pure functions,
and perform common-subexpression elimination for pure function calls, they cannot
always do this for pre-compiled libraries, which generally do not expose this information,
thus preventing optimizations that involve those external functions.

• Some compilers, such as gcc, add extra keywords for a programmer to explicitly mark
external functions as pure, to enable such optimizations. Fortran 95 allows functions to be
designated "pure" in order to allow such optimizations.
Functional Programming:
Recursion
• Iteration in functional languages is usually accomplished via recursion.

• Recursion may require maintaining a stack, and thus may lead to inefficient memory consumption,
but tail recursion can be recognized and optimized by a compiler into the same code used to
implement iteration in imperative languages.

• The Scheme programming language standard requires implementations to recognize and optimize
tail recursion.

• Tail recursion optimization can be implemented by transforming the program into continuation
passing style during compilation, among other approaches.

• Common patterns of recursion can be factored out using higher order functions, catamorphisms and
anamorphisms, which "folds" and "unfolds" a recursive function call nest.

• Using such advanced techniques, recursion can be implemented in an efficient manner in functional
programming languages.
Functional Programming:
Eager vs. Lazy Evaluation
• Functional languages can be categorized by whether they use strict (eager) or non-strict (lazy)
evaluation, concepts that refer to how function arguments are processed when an expression
is being evaluated. Under strict evaluation, the evaluation of any term containing a failing
subterm will itself fail. For example, the expression
print length([2+1, 3*2, 1/0, 5-4])

• will fail under eager evaluation because of the division by zero in the third element of the list.
Under lazy evaluation, the length function will return the value 4 (the length of the list), since
evaluating it will not attempt to evaluate the terms making up the list.

• Eager evaluation fully evaluates function arguments before invoking the function. Lazy
evaluation does not evaluate function arguments unless their values are required to evaluate
the function call itself.

• The usual implementation strategy for lazy evaluation in functional languages is graph
reduction. Lazy evaluation is used by default in several pure functional languages, including
Miranda, Clean and Haskell.
Functional Programming:
Type Inference
• Especially since the development of Hindley–Milner type inference in the 1970s,
functional programming languages have tended to use typed lambda calculus, as
opposed to the untyped lambda calculus used in Lisp and its variants (such as Scheme).

• Type inference, or implicit typing, refers to the ability to deduce automatically the type
of the values manipulated by a program. It is a feature present in some strongly
statically typed languages.

• The presence of strong compile-time type checking makes programs more reliable,
while type inference frees the programmer from the need to manually declare types to
the compiler.

• Type inference is often characteristic of — but not limited to — functional programming


languages in general. Many imperative programming languages have adopted type
inference in order to improve type safety.
Functional Programming:
In Non-functional Languages
• It is possible to employ a functional style of programming in languages that are not
traditionally considered functional languages.

• Some non-functional languages have borrowed features such as higher-order


functions, and list comprehensions from functional programming languages. This
makes it easier to adopt a functional style when using these languages.

• Functional constructs such as higher-order functions and lazy lists can be obtained in C+
+ via libraries, such as in FC++.

• In C, function pointers can be used to get some of the effects of higher-order functions.

• Many object-oriented design patterns are expressible in functional programming terms:


for example, the Strategy pattern dictates use of a higher-order function, and the
Visitor pattern roughly corresponds to a catamorphism, or fold.
Logic and Rule based Programming Paradigm
Logic and rule based
• We now examine a radically different paradigm for programming:
declarative programming
– rather than writing control constructs (loops, selection statements,
subroutines)
– you specify knowledge and how that knowledge is to be applied through a
series of rules
– the programming language environment uses one or more built-in
methods to reason over the knowledge and prove things (or answer
questions)
• in logic programming, the common approach is to apply the methods of resolution
and unification
• While these languages have numerous flaws, they can build
powerful problem solving systems with little programming
expertise
– they have been used extensively in AI research
Terminology
• Logic Programming is a specific type of a more general
class: production systems (also called rule-based
systems)
– a production system is a collection of facts (knowledge), rules
(which are another form of knowledge) and control strategies
– we often refer to the collection of facts (what we know) as
working memory
– the rules are simple if-then statements where the condition
tests values stored in working memory and the action (then
clause) manipulates working memory (adds new facts, deletes
old facts, modifies facts)
– the control strategies help select among a set of rules that
match – that is, if multiple rules have matching conditions,
the control strategies can help decide which rule we select
this time through
– there are other control strategies as well – whether we work
from conditions to conclusions or from conclusions to
conditions (forward, backward chaining respectively)
Logic Programming
• Also known as declarative programming.
• Mostly synonymous with the Prolog language because it
is the only widely used language for logic programming.
• A declarative program does not have code, instead it
defines two pieces of knowledge
– facts – statements that are true.
– rules – if-then statements that are truth preserving.
• We use the program to prove if a statement is true
and/or answer questions.
• The reason this works is that Prolog has built-in problem
solving processes called resolution and unification
– in fact Prolog is not so much a programming language as it is a
tool, but it does have some programming language features
that make it mildly programmable
Background for Logic
• A proposition is a logical statement that is only made if it is true
– Today is Tuesday
– The Earth is round
• Symbolic logic uses propositions to express ideas, relationships
between ideas and to generate new ideas based on the given
propositions
• Two forms of propositions are
– Atomic propositions
– Compound terms (multiple propositions connected through the logical
operators of and, or, not, and implies)
• Propositions will either be true (if stated) or something to prove
or disprove (determine if it is true) – we do not include
statements which are false
• For symbolic logic, we use 1st order predicate calculus
– statements include predicates like round(x) where this is true if we can find
an x that makes it true such as round(Earth) or round(x) when x = Earth
– you might think of a predicate as a Boolean function except that rather
than returning T or F, it finds an x that makes it true
Logic Operators – Equivalence means that
both expressions have
identical truth tables
Name Symbol Example Meaning – Implication is like an if-
negation not a then statement
 a
• if a is true then b is true
conjunction  ab a and b • note that this does not
necessarily mean that if
disjunction  ab a or b a is false that b must
equivalence  ab a is equivalent also be false
to b – Universal quantifier says
that this is true no matter
implication  ab a implies b what x is
 ab b implies a – Existential quantifier says
that there is an X that
universal  X.P For all X, P is fulfills the statement
true
existential  X.P There exists a X.(woman(X)  human(X))
value of X – if X is a woman, then X is a human
such that P is
true X.(mother(mary, X)  male(X))
– Mary has a son (X)
Clausal Form
• To use resolution, all statements must be in clausal form
– B1  B2  …  Bn  A1  A2  …  Am
• B1 or B2 or … or Bn is true if A1and A2 and … and Am are all true
– the left hand side is the consequent (what we are trying to prove) and the
right hand side is the antecedent (what conditions must hold true)
– notice we have turned the if-then statement around,
– We must modify our knowledge so that:
• existential quantifiers are not required (eliminate all of them)
• universal quantifiers are implied (by replacing each with a specific
variable)
• no negations (all negations must be removed)
– We break down our statements to have a single item on the left
• the above statement is broken into multiple statements such as
– B 1  A1  A 2  …  A m
– B 2  A1  A 2  …  A m …
– Bn  A1  A2  …  Am
• note that propositions and predicates by themselves are already in
clausal form, such as round(Earth) and Sunny
Resolution and Unification
• Given a collection of knowledge
– we will want to prove certain statements are true or answer questions
• For instance, from the previous example, we might ask
– who is Bob’s grandfather?
– is Sue Barbara’s parent?
• How can this be done? Through backward chaining through rules
• Here is how backward chaining works
– we want to prove that A is true
– find a rule with A on its LHS and whatever is on the rule’s RHS must now
be proven to be true, so we add the items on the RHS to a list of things we
are trying to prove
– repeat until
• we match something that we know is true to our list, then
remove the item
• we run out of items on our list, then we are done, we have
proven A is true
• To complicate matters, predicates (e.g., round(X)) need to be
unified, that is, to prove round(X) is true, we have to find some X
where we know it is true, for instance, round(Earth)
Complete Logic Example
If we want to find out what would
Assume that we know the following about pets:
make a good indoor pet, we ask
poodle(COCOA) indoorpet(?)
setter(BIG)
terrier(SCOTTY) This requires finding pet(X) and small(X)
(find an X to make both predicates true)
dog(X)  poodle(X) (poodles are dogs) pet(X) is implied by dog(X),
dog(X) is implied by terrier(X),
dog(X)  setter(X) (setters are dogs)
SCOTTY is a terrier so SCOTTY
dog(X)  terrier(X) (terriers are dogs) is a dog so SCOTTY is a pet
small(X)  poodle(X) (poodles are small)
small(X)  terrier(X) (terriers are small) Can we find if SCOTTY is small?
small(SCOTTY) is implied
big(X)  setter(X) (setters are big)
by terrier(SCOTTY) which we
pet(X)  dog(X) (dogs are pets) already know is true, therefore,
indoorpet(X)  pet(X) and small(X) since terrier(SCOTTY) is true, small(SCOTTY)
(small pets are indoor pets) and pet(SCOTTY)
outdoorpet(X)  pet(X) and big(X) are true, so indoorpet(SCOTTY) is
True
(big pets are outdoor pets)
Continuing with this process
will also prove that indoorpet(COCOA)
is true.
poodle

setter

terrier
PROLOG
• PROLOG is a programming language that allows the
programmer to specify declarative statements only
– declarative statements (things you are declaring) fall into 2
categories
• predicates/propositions that are true
• clauses (truth preserving rules in clausal form)
– once specified, the programmer then introduces questions to
be answered
• PROLOG uses resolution (backward chaining) and unification to
perform the problem solving automatically
• PROLOG was developed in France and England in the
late 70s
– the intent was to provide a language that could accommodate
logic statements and has largely been used in AI but also to a
lesser extent as a database language or to solve database
related problems
Elements of Prolog
• Terms – constant, variable, structure
– constants are atoms or integers (atoms are like those symbols
found in Lisp)
– variables are not bound to types, but are bound to values when
instantiated (via unification)
– an instantiation will last as long as it takes to complete a goal
• proving something is true, or reaching a dead end with the current
instantiation
– structures are predicates and are represented as
• functor(parameter list) where functor is the name of the predicate
• All statements in Prolog consist of clauses
– headed clauses are rules
– headless clauses are statements that are always true
• in reality, a headless clause is a rule whose condition is always true
– all clauses must end with a period
Rules
• All rules are stated in Horn clause form
– the consequence comes first
• the symbol :- is used to separate the consequence from the antecedent
– And is denoted by , and Or is denoted by ; or separating the
rule into two separately rules
– variables in rules are indicated with upper-case letters
– rules end with a .
– examples:
• parent(X, Y) :- mother(X, Y).
• parent(X, Y) :- father(X, Y).
• grandparent(X, Z) :- parent(X, Y), parent(Y, Z).
• sibling(X, Y) :- mother(M, X), mother(M, Y), father(F, X), father(F, Y).
– we can use _ as a wildcard meaning this is true if we can find
any clause that fits
• father(X) :- father(X, _), male(X).
– X is a father if X is male and is someone’s father
Other Language Features
• Assignment statements are available using the is operator
– A is B / 17 + C.
• this works if B and C are instantiated and A is not
• however, is does not work like a true assignment statement
– you can not do x is x + y – this can never be true!
– we might use the assignment operator in a rule such as
• distance(X,Y) :- speed(X,Speed), time(X,Time), Y is Speed * Time
• List structures are also available using [ ] marks
– as in new_list([apple, prune, grape, kumquat]).
– this is not a binding of new_list to the values, but instead
new_list is a predicate with a true instance of the predicate
being the parameter [apple, prune, grape, kumquat]
• lists can also be represented as a head and tail using | to separate the
two parts similar to how Lisp uses CAR and CDR
More Prolog Examples
predecessor(X,Y) :- parent(X,Y); parent(X,Z), predecessor(Z,Y).
// X is a predecessor of Y if X is Y’s parent or
// if X is parent of someone else who is a predecessor of Y

Using Not: Notice the use of “not”


dog(X) :- poodle(X). here – in Prolog, x != y is
dog(X) :- terrier(X). available but ~foo(x) is not
likes(X,Y) :- dog(X), dog(Y), not (X=Y).
That is, we only declare
// can also be written as X =\= Y statements that are true, we
cannot declare the negation
of statements that are false
Database example: imagine we have a collection of terms:
record(name, yearborn, salary)
Successful person is someone who either makes > $50000 in salary
or was born after 1980 and is making more than $40000.
success(X) :- record(X, Y, Z), Z > 50000;
record(X, Y, Z), Y > 1980, Z > 40000.
Additional Prolog Examples
Defining Max:
max(X,Y,M) :- X > Y, M is X.
max(X,Y,M) :- Y >= X, M is Y.

Defining GCD:
gcd(X,Y,D) :- X=Y, D is X.
gcd(X,Y,D) :- X<Y, Y1 is Y - X, gcd(X, Y1, D).
gcd(X,Y,D) :- X>Y, gcd(Y, X, D).

Two List examples

Defining Length:
length([ ], 0). // empty list has a length of 0
length([ _ | Tail, N) :- length(Tail, N1), N is 1 + N1. // a list that has an
// item _ and a Tail is length N if the length of Tail is N1 where N = 1 + N1

Sum of the items in a list:


sum([ ], 0). // sum of an empty list is 0
sum([X | Tail], S) :- sum(Tail, S1), S is X + S1.
Advantages of Prolog
• There are several advantages to using Prolog
– ability to create automated problem solvers merely by listing knowledge
– a shortcut way to build and query a database
– solving significantly difficult problems with minimal code:
Deriving the permutations of a list List:
perm(List,[H|Perm]):-delete(H,List,Rest),perm(Rest,Perm).
perm([ ],[ ]).
delete(X,[X|T],T).
delete(X,[H|T],[H|NT]):-delete(X,T,NT).
Sorting a list of values stored in List:
insert_sort(List,Sorted):-i_sort(List,[],Sorted).
i_sort([ ],Acc,Acc).
i_sort([H|T],Acc,Sorted):-insert(H,Acc,NAcc),i_sort(T,NAcc,Sorted).
insert(X,[Y|T],[Y|NT]):-X>Y,insert(X,T,NT).
insert(X,[Y|T],[X,Y|T]):-X=<Y.
insert(X,[],[X]).
A naïve sort (inefficient, but simple):
naive_sort(List,Sorted):-perm(List,Sorted),is_sorted(Sorted).
is_sorted([ ]).
is_sorted([ _ ]).
is_sorted([X,Y|T]):-X=<Y,is_sorted([Y|T]).
Deficiencies of Prolog
• Lack of control structures
– Prolog offers built-in control of resolution and unification
• you often have to force a problem into the resolution mold to solve it with Prolog
(most problems cannot or should not be solved in this way)
• Inefficiencies of resolution
– resolution, as a process, is intractable (O(2n) for n clauses)
• useful heuristics could be applied to reduce the complexity, but there is no way to
apply heuristics in Prolog
– they would just be additional rules that increases the size of n!
• Closed world assumption
– in any form of logic reasoning, if something is not known, it is assumed to
be false and everything is either true or false
• Negation is difficult to represent
– since there is no NOT in Prolog, how do we represent NOT?
• recall that anything explicitly stated must be true so we cannot specify NOT something
as something would then be false
• we can represent A != B, but we cannot represent ~dog(X).
Rule-based Approaches
• Three of Prolog’s deficiencies can be eliminated (or lessened)
– heuristics can be applied to improve efficiency
• not necessarily reduce the complexity below O(2n) but improve it
– uncertainty can be expressed by adding certainty factors or probabilities to
data, rules and conclusions
– use both forward and backward chaining
• Rule-based systems are less restrictive than the strictly logic-based
approach in Prolog
– by moving away from the formal logic approach however, doubts can arise
from any results generated by such a system
• that is, we can not be sure of the truth of something proven when the system
contains non-truth-preserving rules and uncertain data
– is it useful to move away from the strict logic-based approach given this
uncertainty?
• since nearly everything in the world has uncertainty, my answer is YES
• The rule-based approach is largely the same as in Prolog:
– declare knowledge, provide rules, and ask questions to be answered, but
most rule-based languages provide mechanisms for control strategies
Case Study
• A case study: Retail Sales application
Thank You

You might also like