Programming Languages: A Brief History & Introduction to Lambda Calculus - Prof. Carlos A., Study notes of Programming Languages

Lecture notes on programming languages, focusing on the history of various programming languages and an introduction to lambda calculus. Topics include the first 'programmer' ada lovelace, imperative, object-oriented, concurrent object-oriented, functional, and scripting languages. Lambda calculus is introduced with its syntax and semantics, and the concept of free and bound variables is discussed.

Typology: Study notes

Pre 2010

Uploaded on 08/09/2009

koofers-user-p2x-1
koofers-user-p2x-1 🇺🇸

10 documents

1 / 5

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CSCI.4430/6969 Programming Languages
Lecture Notes
August 28, 2006
1 Brief History of Programming Languages
Ada Augusta, the Countess of Lovelace, the daughter of the poet Lord Byron, is attributed as being the
first “programmer” ever, using Babbage’s Analytical Engine, circa 1843.
Imperative programming languages include: Fortran (Backus 1954) as one of the first “high-level”
(compiled) programming languages created at IBM and used for numerical computing, Algol (Naur 1958)
the precursor of many of today’s programming languages, Cobol (Hopper 1959) for business applications,
BASIC (Kemeny and Kurtz 1964) and Pascal (Wirth 1970) developed for teaching computer programming,
C (Kernighan and Ritchie 1971) used to program the UNIX operating system at Bell Labs, and Ada
(Whitaker 1979) for concurrent applications.
Object-oriented programming languages include: Simula (Dahl and Nygaard 1967) used for computer
simulations, Smalltalk (Kay 1980) where everything is an object, C++ (Stroustrop 1980) to introduce
classes and objects to C programmers, Eiffel (Meyer 1985) which includes assertions and invariants, Java
(Gosling 1994) initially created to program appliances and later used and introduced to program dynamic
web content, and C# (Hejlsberg 2000), Microsoft’s response to Java.
Concurrent object (actor) oriented programming languages include: PLASMA (Hewitt 1975), Act
(Lieberman 1981), ABCL (Yonezawa 1988), Actalk (Briot 1989), Erlang (Armstrong 1990), E (Miller et
al 1998) and SALSA (Varela and Agha 1999). Scheme (Sussman and Steele 1975) was developed in an
attempt to understand the actor model.
Functional programming languages include: Lisp (McCarthy 1958), ML (Milner 1973), and Haskell
(Hughes et al 1987). The most well-known logic programming language is Prolog (Colmerauer and Roussel
1972) created to process natural language (French). Oz (Smolka 1995) is a declarative programming
language that can be used to combine multiple paradigms, e.g., functional, object-oriented, and logical
programming. Lua (Ierusalimschy et al 1994) is a lightweight programming language with extensible
semantics.
Scripting languages include: Python (van Rossum 1985), Perl (Wall 1987), Tcl (Ousterhout 1988),
JavaScript (Eich 1995), PHP (Lerdorf 1995), and Ruby (Matsumoto 1995), an object-oriented scripting
language.
2 Lambda Calculus
The lambda calculus created by Church and Kleene in the 1930’s is at the heart of functional programming
languages. It is Turing-complete, that is, any computable function can be expressed and evaluated using
the calculus. It is useful to study programming language concepts because of its high level of abstraction.
We will briefly motivate the calculus and introduce its syntax and semantics.
The mathematical notation for defining a function is with a statement such as
f(x) = x2, f :ZZ,
1
pf3
pf4
pf5

Partial preview of the text

Download Programming Languages: A Brief History & Introduction to Lambda Calculus - Prof. Carlos A. and more Study notes Programming Languages in PDF only on Docsity!

CSCI.4430/6969 Programming Languages

Lecture Notes

August 28, 2006

1 Brief History of Programming Languages

Ada Augusta, the Countess of Lovelace, the daughter of the poet Lord Byron, is attributed as being the first “programmer” ever, using Babbage’s Analytical Engine, circa 1843. Imperative programming languages include: Fortran (Backus 1954) as one of the first “high-level” (compiled) programming languages created at IBM and used for numerical computing, Algol (Naur 1958) the precursor of many of today’s programming languages, Cobol (Hopper 1959) for business applications, BASIC (Kemeny and Kurtz 1964) and Pascal (Wirth 1970) developed for teaching computer programming, C (Kernighan and Ritchie 1971) used to program the UNIX operating system at Bell Labs, and Ada (Whitaker 1979) for concurrent applications. Object-oriented programming languages include: Simula (Dahl and Nygaard 1967) used for computer simulations, Smalltalk (Kay 1980) where everything is an object, C++ (Stroustrop 1980) to introduce classes and objects to C programmers, Eiffel (Meyer 1985) which includes assertions and invariants, Java (Gosling 1994) initially created to program appliances and later used and introduced to program dynamic web content, and C# (Hejlsberg 2000), Microsoft’s response to Java. Concurrent object (actor) oriented programming languages include: PLASMA (Hewitt 1975), Act (Lieberman 1981), ABCL (Yonezawa 1988), Actalk (Briot 1989), Erlang (Armstrong 1990), E (Miller et al 1998) and SALSA (Varela and Agha 1999). Scheme (Sussman and Steele 1975) was developed in an attempt to understand the actor model. Functional programming languages include: Lisp (McCarthy 1958), ML (Milner 1973), and Haskell (Hughes et al 1987). The most well-known logic programming language is Prolog (Colmerauer and Roussel

  1. created to process natural language (French). Oz (Smolka 1995) is a declarative programming language that can be used to combine multiple paradigms, e.g., functional, object-oriented, and logical programming. Lua (Ierusalimschy et al 1994) is a lightweight programming language with extensible semantics. Scripting languages include: Python (van Rossum 1985), Perl (Wall 1987), Tcl (Ousterhout 1988), JavaScript (Eich 1995), PHP (Lerdorf 1995), and Ruby (Matsumoto 1995), an object-oriented scripting language.

2 Lambda Calculus

The lambda calculus created by Church and Kleene in the 1930’s is at the heart of functional programming languages. It is Turing-complete, that is, any computable function can be expressed and evaluated using the calculus. It is useful to study programming language concepts because of its high level of abstraction. We will briefly motivate the calculus and introduce its syntax and semantics. The mathematical notation for defining a function is with a statement such as

f (x) = x^2 , f : Z → Z,

where Z is the set of all integers. The first Z is called the domain of the function, or the set of values x can take. The second Z is called the range of the function, or the set containing all possible values of f (x). Suppose f (x) = x^2 and g(x) = x + 1. Traditional function composition is defined as

f ◦ g = f (g(x)).

With our functions f and g,

f ◦ g = f (g(x)) = f (x + 1) = x^2 + 2x + 1.

Similarly g ◦ f = g (f (x)) = g(x^2 ) = x^2 + 1. Therefore, function composition is not commutative. In lambda (λ) calculus, we can use a different notation to define these same concepts. To define a function f (x) = x^2 , we instead write λx.x^2.

Similarly for g(x) = x + 1 we instead write λx.x + 1.

To describe a function application such as f (2) = 4, we write

(λx.x^2 2) ⇒ 22 ⇒ 4.

The syntax for lambda calculus expressions is

e ::= v – variable | λv.e – lambda expression | (e e) – procedure call

The semantics of the lambda calculus, or the way of evaluating or simplifying expressions, is defined by the rule (λx.E M ) ⇒ E{M/x}.

The new expression E{M/x} can be read as “replace ‘fresh’ x’s in E with M ”. Informally, a “fresh” x is an x that is not nested inside another lambda expression. We will cover free and bound variable occurrences in detail later on. For example, in the expression (λx.x^2 2),

E = x^2 and M = 2. To evaluate the expression, we replace x’s in E with M , to obtain

(λx.x^2 2) ⇒ 22 ⇒ 4.

In lambda calculus, all functions may only have one variable. Functions with more than one variable may be expressed as a function of one variable through currying. Suppose we have a function of two variables expressed in the normal way

h(x, y) = x + y, h : (Z × Z) → Z.

With currying, we can input one variable at a time into separate functions. The first function will take the first argument, x, and return a function that will take the second variable, y, and will in turn provide the desired output. To create the same function with currying, let

f : Z → (Z → Z)

the second x is bound to λx, because it is part of the expression defining that function, which is the function f (x) = x^2. The final x, however, is not bound to any function definition, so is considered free. Do not be confused by the fact that the variables have the same name. They are in different scopes, so they are totally independent of each other. An equivalent C program could look like this:

int f(int x) { return x*x; }

int main() { int x; ... x = x + 1; return f(x); }

In this example, the x in f could have been substituted for y or any other variable name without changing the output of the program. In the same way, the lambda expression

(λx.x^2 x + 1)

is identical to the expression (λy.y^2 x + 1),

since the final x is unbound, or free. To simplify the expression

(λx.(λx.x^2 x + 1) 2)

You could let E = (λx.x^2 x + 1) and M = 2. The only free x in E is the final one so the correct reduction is (λx.x^2 2 + 1).

The x in x^2 is bound, so it is not replaced. However, things get more complicated. It is possible when performing β -reduction to inadvertently change a free variable into a bound variable, which changes the meaning of the expression. In the statement

(λx.λy.(x y) (y w)),

the second y is bound to λy and the final y is free. Taking E = λy.(x y) and M = (y w), we could mistakenly arrive at the simplified expression

λy.((y w) y).

But now both the second and third y’s are bound, because they are both a part of of the λy function definition. This is wrong because one of the y’s should remain free as it was in the original expression. To get around this, we can change the λy expression to a λz expression

(λx.λz.(x z) (y w)),

which again does not change the meaning of the expression. This process is called α -renaming. Now when we perform the β -reduction, the original two y variables are not confused. The result is

λz.((y w) z).

Here, the free y remains free.

Exercises

  1. α-convert the outer-most x to y in the following λ-calculus expressions, if possible:

(a) λx.(λx.x x) (b) λx.(λx.x y)

  1. β-reduce the following λ-calculus expressions, if possible:

(a) (λx.λy.(x y) (y w)) (b) (λx.(x x) λx.(x x))