This document discusses first-class functions and lambda calculus. It begins with an overview of Alonzo Church and the origins of lambda calculus. It then covers first-class functions in JavaScript, functions as objects in Java, and first-class functions in Scala. The document also discusses generic higher-order functions and control abstraction.
4. Graded Assignment 1
Algebraic datatypes in C
Dynamic dispatch in C
Important dates
Deadline: April 2, 2013 23:59
Extension: April 5, 2013 23:59
Submitting after extension date is not possible
Maximum penalty for submitting after deadline: 6 points
Minimum grade needed: 4
Grade: 70% unit tests, 30% check lists
Grade for GAs: average of four assignments
5. Alonzo Church (June 14, 1903 – August 11, 1995) was
an American mathematician and logician who made major
contributions to mathematical logic and the foundations of
theoretical computer science. He is best known for the
lambda calculus, Church–Turing thesis, proving the
undecidability of the Entscheidungsproblem, Frege–Church
ontology, and the Church–Rosser theorem.
The lambda calculus emerged in his famous 1936 paper showing the unsolvability of
the Entscheidungsproblem. This result preceded Alan Turing's famous work on the
halting problem, which also demonstrated the existence of a problem unsolvable by
mechanical means. Church and Turing then showed that the lambda calculus and the
Turing machine used in Turing's halting problem were equivalent in capabilities, and
subsequently demonstrated a variety of alternative "mechanical processes for
computation." This resulted in the Church–Turing thesis.
The lambda calculus influenced the design of the LISP programming language and
functional programming languages in general. The Church encoding is named in his
honor.
http://en.wikipedia.org/wiki/Alonzo_Church
6. Outline
Lambda calculus
First-class functions in JavaScript
Functions as objects in Java
First-class functions in Scala
Generic, higher-order functions
Control abstraction
8. Syntax
• Variables: x
• Functions: λ x . M
Lambda Calculus
• Application: (M N)
Semantics
• Beta reduction: (λ x . M) N ≡ M[x := N]
Example
• ((λ c . (λ x . c)) 1) 2 ≡ (λ x . 1) 2 ≡ 1
9. Free Variables Lambda Calculus
• fvs(x) ≡ {x}
• fvs(λ x . M) ≡ fvs(M) / {x}
• fvs(M N) ≡ fvs(M) ∪ fvs(N)
Example
• fvs(λ c . x (λ x . z c)) ≡ {x, z}
10. Lambda Calculus
Substitution
• x [x := N] ≡ N
• y [x := N] ≡ y if x ≢ y
• (λ x . M) [x := N] ≡ λ x . M
• (λ y . M) [x := N] ≡ λ y . (M [x := N]) if x ≢ y, y ∉ fvs(N)
• (M N) [x := P] ≡ (M[x := P])(N[x := P])
Example
• (λ x . (λ z . x z) (x z)) [z := k] ≡ (λ x . (λ z . x z) (x k))
12. Lambda = first-class function
Beta reduction = function evaluation
Lambda calculus = essence of functional programming
instantiated in many modern programming languages
13. First-order functions
• Function definition Functions are Values
• Function call
First-class functions
• unnamed function literals
(x: Int) => x + 1
• pass functions around as values: return as
result, pass as parameter, store in data
structure
14. Code reuse
• name and parameterize
expressions and statements
Functional abstraction in Java
• methods
Functional abstraction in Scala
• nested functions
• function literals
• function values
16. // Print the name and value of each property of o. Return undefined.
function printprops(o) {
for ( var p in o)
console.log(p + ": " + o[p] + "n");
}
// Compute the distance between Cartesian points (x1,y1) and (x2,y2).
function distance(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
// A recursive function (one that calls itself) that computes factorials
// Recall that x! is the product of x and all positive integers less than it.
function factorial(x) {
if (x <= 1)
return 1;
return x * factorial(x - 1);
}
Named Function Definitions
17. Anonymous Function Expressions
// This function expression defines a function that squares its argument.
// Note that we assign it to a variable
var square = function(x) {
return x * x;
}
// Function expressions can include names, which is useful for recursion.
var f = function fact(x) {
if (x <= 1)
return 1;
else
return x * fact(x - 1);
};
// Function expressions can also be used as arguments to other functions:
data.sort(function(a, b) { return a - b; });
// Function expressions are sometimes defined and immediately invoked:
var tensquared = (function(x) { return x * x; }(10));
18. var incrementer = Nested functions: Closures
function (base) {
return function (x) {
return x + base;
};
};
var inc3 = incrementer(3);
inc3(39);
remember value of base
incrementer = base . ( x . (x + base))
inc3 = incrementer 3;
inc3 39
In lambda notation
19. var scope = "global scope"; // A global variable Closures
function checkscope() {
var scope = "local scope"; // A local variable
function f() {
return scope;
} // Return the value in scope here
return f();
}
checkscope() // => "local scope"
var scope = "global scope"; // A global variable
function checkscope() {
var scope = "local scope"; // A local variable
function f() {
return scope;
} // Return the value in scope here
return f;
}
checkscope()() // What does this return?
20. var uniqueInteger = (function() { // Define and invoke
var counter = 0; // Private state of function below
return function() {
return counter++;
}; Closures with state
}());
function counter() {
var n = 0;
return {
count: function() { return n++; },
reset: function() { n = 0; }
};
}
var c = counter(), d = counter(); // Create two counters
c.count() // => 0
d.count() // => 0: they count independently
c.reset() // reset() and count() methods share state
c.count() // => 0: because we reset c
d.count() // => 1: d was not reset
21. // This function returns a function that always returns v
function constfunc(v) { return function() { return v; }; }
// Create an array of constant functions:
var funcs = [];
for(var i = 0; i < 10; i++) funcs[i] = constfunc(i);
// The function at array element 5 returns the value 5.
funcs[5]() // => 5
Accidental closure state
// Return an array of functions that return the values 0-9
function constfuncs() {
var funcs = [];
for ( var i = 0; i < 10; i++)
funcs[i] = function() { return i; };
return funcs;
}
var funcs = constfuncs();
funcs[5]() // What does this return?
22. function compose(f, g) {
return function() {
// We use call for f because we're passing a single value
// and apply for g because we're passing an array of values.
return f.call(this, g.apply(this, arguments));
};
}
var square = function(x) {
return x * x;
Higher-Order Functions
};
var sum = function(x, y) {
return x + y;
};
var squareofsum = compose(square, sum);
squareofsum(2, 3) // => 25
23. function incList(xs) {
var ys = [];
for(i in xs) { ys[i] = xs[i] + 1; }
return ys;
}
incList([1, 2, 3]) // returns [2, 3, 4]
function map(f, xs) {
Higher-Order Functions
var ys = [];
for(i in xs) { ys[i] = f(xs[i]); }
return ys;
}
function incList2(xs) {
return map(function (x) { return x + 1; }, xs);
}
incList2([1, 2, 3]) // returns [2, 3, 4]
31. Re-occurring patterns
• transform every element of a list
• verify property of all elements of a list
• extract elements satisfying some criterion
• combining elements of a list using some
operator
Higher-order functions
• direct, reusable definitions of such patterns
32. def inc(xs: IntList): IntList = xs match {
case Nil() => Nil()
case Cons(y, ys) => Cons(y + 1, inc(ys))
}
def square(xs: IntList): IntList = xs match {
case Nil() => Nil()
case Cons(y, ys) => Cons(y * y, square(ys))
}
Transform each element of a list
33. Factor out the transformation
def map(xs: IntList, f: Int => Int): IntList = xs match {
case Nil() => Nil()
case Cons(y, ys) => Cons(f(y), map(ys, f))
}
def inc(xs: IntList) = map(xs, ((x:Int) => x + 1))
def square(xs: IntList) = map(xs, ((x:Int) => x * x))
34. Lists in Scala Library
val fruit : List[String] =
List("apples", "oranges", "pears")
val nums: List[Int] = List(1, 2, 3, 4)
val diag3: List[List[Int]] =
List(
List(1, 0, 0),
List(0, 1, 0),
List(0, 0, 1))
val empty = List()
Lists are polymorphic: parameterized with type of elements
35. Factor out type
A => B : type of functions from type A to type B
def map[A,B](xs: List[A], f: A => B): List[B] = xs match {
case List() => List()
case y :: ys => f(y) :: map(ys, f)
}
val l = map(List(1, 2, 3), ((x: Int) => x + 1))
Polymorphic function: parameterized with types
41. def sum(xs: IntList): Int = xs match {
case Nil() => 0
case Cons(y, ys) => y + sum(ys)
}
def product(xs: IntList): Int = xs match {
case Nil() => 1
case Cons(y, ys) => y * product(ys)
}
Combining Elements
42. Factor out operator
def foldRight(xs: IntList, z: Int, op: (Int,Int)=>Int): Int =
xs match {
case Nil() => z
case Cons(y, ys) => op(y, foldRight(ys, z, op))
}
def sum(xs: IntList): Int =
foldRight(xs, 0, (x: Int, y: Int) => x + y)
def product(xs: IntList): Int =
foldRight(xs, 1, (x: Int, y: Int) => x * y)
43. def foldLeft(xs: IntList, z: Int, op: (Int,Int) => Int): Int =
xs match {
case Nil() => z
case Cons(y, ys) => foldLeft(ys, op(z, y), op)
}
def sumF(xs: IntList): Int =
foldLeft(xs, 0, (x: Int, y: Int) => x + y)
Tail recursive folding
44. Factor out type
def foldLeft[A,B](xs: List[A], z: B, op: (B,A) => B): B =
xs match {
case List() => z
case y :: ys => foldLeft(ys, op(z, y), op)
}
45. scala> ("" /: words) (_ +" "+ _)
res46: java.lang.String = the quick brown fox
scala> (words.head /: words.tail) (_ +" "+ _)
res47: java.lang.String = the quick brown fox
(z /: List(a, b, c)) (op)
equals
op(op(op(z, a), b), c) Fold left in Scala Library
List(a, b, c).foldLeft(z)(op)
46. sum(List(a, b, c)) equals 0 + a + b + c
scala> def sum(xs: List[Int]): Int = (0 /: xs) (_ + _)
sum: (List[Int])Int
Folding Lists
product(List(a, b, c)) equals 1 * a * b * c
scala> def product(xs: List[Int]): Int = (1 /: xs) (_ * _)
sum: (List[Int])Int
47. Fold Right
(List(a, b, c) : z) (op)
equals
op(a, op(b, op(c, z)))
List(a, b, c).foldRight(z)(op)
48. Map defined with Fold
def map[A,B](xs: List[A], f : A => B): List[B]
= (xs : List[B]())(
(x: A, ys: List[B]) => f(x) :: ys
)
Filter defined with Fold
def filter[A](xs: List[A], p : A => Boolean): List[A]
= (xs : List[A]())(
(x: A, ys: List[A]) => if(p(x)) x :: ys else ys
)
49. Re-occurring patterns
• transform every element of a list
• verify property of all elements of a list
• extract elements satisfying some criterion
• combining elements of a list using some
operator
Higher-order functions
• direct, reusable definitions of such patterns
50. Higher-order functions
• reducing code duplication, simplifying client code
Currying
• partial function applications
Writing new control structures
• growing the language
By-name parameters
• lazy evaluation
51. Reading & Programming in Week 6
Reading
Sebesta Chapter 15: Functional Programming
Languages
Java Script TGP Chapter 4: Functions
WebLab:
C, JavaScript, Scala tutorials
Graded Assignment 1: Dynamic Dispatch in C
(deadline 2 April 2013, 23:59)
Week 7: Polymorphism