Today:
Homework 1 solutions.
Reading questions from Louden.
Lambda calculus.
For next time you should:
Read from Sipser and answer the questions below.
Prepare for a quiz.
Start Homework 2.
This discussion follows http://en.wikipedia.org/wiki/Lambda_calculus
The lambda calculus is a mathematical abstraction of computation. You can also think of it as a very small programming language.
Here's the syntax: a lambda term can be:
A variable, like x.
A lambda abstraction, written λx.t, where x is a variable and t is a lambda term.
An application, written t s, where t and s are lambda terms.
"Intuitively, a lambda abstraction λx.t represents an anonymous function that takes a single input, and the λ is said to bind x in t. An application, t s, represents the application of input s to some function t.
"For example, λx.x represents the identity function and (λx.x)y represents the identity function applied to y. Further, (λx.y) represents the constant function, the function that always returns y, no matter the input. Function application is left-associative, so (λx.x)y z = ((λx.x)y)z."
The semantics of the lambda calculus are based on the idea of a reduction. A lambda term can be reduced to another term according to a set of rules.
The most important rule is beta-reduction, which corresponds to parameter passing.
((λx.t) s) can be reduced to t[x := s], which means t with s substituted for x.
What happens when you reduce these terms:
(λ x.x) y
(λ x.y) x
λ x. f x
(λ x.x x) y
(λ x. x x) λ y. y
(λ x.x x) (λ x.x x)
Here are some that take more than one parameter:
(λ x y. x) (λ x. x x) λ y. y
(λ x y. y x) (λ y. y) λ y. y
The lambda calculus is Turing complete, which means that it can compute the same set of functions as a Turing machine and any other reasonable model of computation.
To "prove" that remarkable claim, we will spend the next two homeworks writing the factorial function using only the lambda calculus.
We'll start today by implementing boolean values and logical functions. But first we need currying.
Functions with more than one parameter are convenient, but not necessary. We can get the same effect by nesting lambda terms. This transformation is called currying after Haskell Curry.
For example, to write a function like add, you could write
λx.λy.x+y
or in Scheme
(lambda (x)
(lambda (y)
(+ x y))
Then to apply it, you need to nest the applications:
((λx.λy.x+y) 3) 4)
or in Scheme
(((lambda (x)
(lambda (y)
(+ x y))) 3) 4)
One nice thing: if you have a function of two parameters and you curry it, you can give it one parameter, and it gives you back a function of one parameter. For example, what is this?
((lambda (x)
(lambda (y)
(+ x y))) 3)
This move is called "partial application."
You are now ready to start Homework 2.
Sipser, page xi: To the student, and pages 1-16
1) What is the central question of complexity theory?
2) Give an example of an application where a computationally hard problem is a good thing.
3) What's the difference between computability theory and complexity theory?
4) Give an example of an automaton that has a practical application.
5) After you read about Sets, do Exercise 0.2 on page 25, "Write a formal description of the following sets."
6) After you read about functions and relations, do Exercise 0.6 on page 26, "Let X be the set..."
7) After you read about graphs, do Exercise 0.8 on page 26, "Consider the undirected graph..."
8) What is a tree? What are leaves?
9) What is a language?