Principles of Programming Languages UNIT I
Principles of Programming Languages UNIT I
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.
• Problem Solving
• What is Programming Language
• Software Design
Role of Programming Languages
T1 Chapter 1
Role of Programming Languages
T1 Chapter 1
• Computer Hardware
• Firmware Computer
• Translators and Firmware Architectures
Virtual Computers and Binding Times
• 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.
• These replaced machine code functions with mnemonics and memory addresses
with symbolic labels.
• 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.
• One might say that a class is a blueprint or factory that describes the nature of
something.
• 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).
• Up to this day, functional programming has not been very popular except
for a restricted number of application areas, such as artificial intelligence.
• 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 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.
• 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.
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
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).
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