Upload
eelco-visser
View
1.229
Download
1
Tags:
Embed Size (px)
Citation preview
TI1220 2012-2013Concepts of Programming Languages
Eelco Visser / TU Delft
Lecture 6: First-Class Functions
Messages from the Lab
Graded Assignment 1Algebraic datatypes in CDynamic dispatch in C
Important datesDeadline: April 2, 2013 23:59Extension: April 5, 2013 23:59
Submitting after extension date is not possibleMaximum penalty for submitting after deadline: 6 pointsMinimum grade needed: 4Grade: 70% unit tests, 30% check listsGrade for GAs: average of four assignments
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
Outline
Lambda calculus
First-class functions in JavaScript
Functions as objects in Java
First-class functions in Scala
Generic, higher-order functions
Control abstraction
Lambda Calculus
Syntax
• Variables: x
• Functions: λ x . M
• Application: (M N)
Semantics
• Beta reduction: (λ x . M) N ≡ M[x := N]
Example
• ((λ c . (λ x . c)) 1) 2 ≡ (λ x . 1) 2 ≡ 1
Lambda Calculus
Free Variables
• 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}
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))
Lambda Calculus
What is the relevance of the lambda calculus?
Lambda = first-class function
Beta reduction = function evaluation
Lambda calculus = essence of functional programming
instantiated in many modern programming languages
First-order functions
• Function definition
• 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
Functions are Values
Code reuse
• name and parameterize expressions and statements
Functional abstraction in Java
• methods
Functional abstraction in Scala
• nested functions
• function literals
• function values
First-Class Functionsin JavaScript
// 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
// This function expression defines a function that squares its argument.// Note that we assign it to a variablevar 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));
Anonymous Function Expressions
var incrementer = function (base) { return function (x) { return x + base; }; };
var inc3 = incrementer(3);
inc3(39);
incrementer = \ base . ( \ x . (x + base))inc3 = incrementer 3;inc3 39
Nested functions: Closures
In lambda notation
remember value of base
var scope = "global scope"; // A global variablefunction 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 variablefunction 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?
Closures
var uniqueInteger = (function() { // Define and invoke var counter = 0; // Private state of function below return function() { return counter++; };}());
function counter() { var n = 0; return { count: function() { return n++; }, reset: function() { n = 0; } };}var c = counter(), d = counter(); // Create two countersc.count() // => 0d.count() // => 0: they count independentlyc.reset() // reset() and count() methods share statec.count() // => 0: because we reset cd.count() // => 1: d was not reset
Closures with state
// This function returns a function that always returns vfunction 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
// Return an array of functions that return the values 0-9function 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?
Accidental closure state
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;};
var sum = function(x, y) { return x + y;};
var squareofsum = compose(square, sum);
squareofsum(2, 3) // => 25
Higher-Order Functions
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) { 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]
Higher-Order Functions
Functions as Objects in Java
Does Java support first-class functions?
interface IntFun { Int apply(Int x)}class Inc implements IntFun { Int apply(Int x) { return x + 1; }}class Foo { void f(IntFun g) { g.apply(...) }} ... foo.f(new Inc) ...
Functions as Objects in Java
First-Class Functionsin Scala
((c: Int) => ((x: Int) => c+x))(1)(2)
evaluation steps:
- ((x: Int) => 1+x) (2)
- 1+2
- 3
Function Literals
scala> var increase = (x: Int) => x + 1increase: (Int) => Int = <function1>
scala> increase(10)res0: Int = 11
scala> increase = (x: Int) => x + 9999increase: (Int) => Int = <function1>
scala> increase(10)res1: Int = 10009
scala> increase.apply(10) res37: Int = 11
Function Values are Objects
<function>(<args>) abbreviates
<function>.apply(<args>)
Generic Higher-Order Functions (in Scala)
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
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
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))
Factor out the transformation
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 in Scala Library
Lists are polymorphic: parameterized with type of elements
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))
Factor out type
Polymorphic function: parameterized with types
A => B : type of functions from type A to type B
scala> List(1, 2, 3) map (_ + 1)res29: List[Int] = List(2, 3, 4)
scala> val words = List("the", "quick", "brown", "fox")words: List[java.lang.String] = List(the, quick, brown, fox)
scala> words map (_.length)res30: List[Int] = List(3, 5, 5, 3)
scala> words map (_.toList.reverse.mkString)res31: List[String] = List(eht, kciuq, nworb, xof)
scala> words map (_.toList)res32: List[List[Char]] = List(List(t,h,e), List(q,u,i,c,k), List(b,r,o,w,n), List(f,o,x))
scala> words flatMap (_.toList)res33: List[Char] = List(t,h,e,q,u,i,c,k,b,r,o,w,n,f,o,x)
Map in Scala Library
def even(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => if(y % 2 == 0) Cons(y, even(ys)) else even(ys)} def primes(xs: IntList): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => if(isPrime(y)) Cons(y, primes(ys)) else primes(ys)}
Select Elements in a List
def filter(xs: IntList, p: Int => Boolean): IntList = xs match { case Nil() => Nil() case Cons(y, ys) => if(p(y)) Cons(y, filter(ys, p)) else filter(ys, p)} def evenF(xs: IntList) = filter(xs, ((x: Int) => x % 2 == 0))def primes(xs: IntList) = filter(xs, isPrime _)
Factor out Predicate
def filter[A](xs: List[A], p: A => Boolean): List[A] = xs match { case List() => List() case y :: ys => if(p(y)) (y :: filter(ys, p)) else filter(ys, p) }
def evenF(xs: List[Int]) = filter[Int](xs, ((x: Int) => x % 2 == 0))def primes(xs: List[Int]) = filter[Int](xs, isPrime _)
Factor out Type of Elements
scala> List(1, 2, 3, 4, 5) filter (_ % 2 == 0)res37: List[Int] = List(2, 4)
scala> words filter (_.length == 3)res38: List[java.lang.String] = List(the, fox)
scala> List(1, 2, 3, 4, 5) partition (_ % 2 == 0)res39: (List[Int], List[Int]) = (List(2, 4),List(1, 3, 5))
scala> List(1, 2, 3, 4, 5) find (_ % 2 == 0)res40: Option[Int] = Some(2)
scala> List(1, 2, 3, 4, 5) find (_ <= 0)res41: Option[Int] = None
scala> List(1, 2, 3, 4,5) takeWhile (_ > 0)res42: List[Int] = List(1, 2, 3)
scala> words dropWhile (_ startsWith "t")res43: List[java.lang.String] = List(quick, brown, fox)
scala> List(1, 2, 3, 4,5) span (_ > 0)res44: (List[Int], List[Int]) = (List(1, 2, 3),List(4, 5))
xs partition p equals (xs filter p, xs filter (!p(_)))
Filtering in Scala Library
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
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)
Factor out operator
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
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) }
Factor out type
(z /: List(a, b, c)) (op)
equals
op(op(op(z, a), b), c)
scala> ("" /: words) (_ +" "+ _)res46: java.lang.String = the quick brown fox
scala> (words.head /: words.tail) (_ +" "+ _)res47: java.lang.String = the quick brown fox
List(a, b, c).foldLeft(z)(op)
Fold left in Scala Library
scala> def sum(xs: List[Int]): Int = (0 /: xs) (_ + _)sum: (List[Int])Int
sum(List(a, b, c)) equals 0 + a + b + c
scala> def product(xs: List[Int]): Int = (1 /: xs) (_ * _)sum: (List[Int])Int
product(List(a, b, c)) equals 1 * a * b * c
Folding Lists
(List(a, b, c) :\ z) (op)
equals
op(a, op(b, op(c, z)))
List(a, b, c).foldRight(z)(op)
Fold Right
def map[A,B](xs: List[A], f : A => B): List[B] = (xs :\ List[B]())( (x: A, ys: List[B]) => f(x) :: ys )
Map 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 )
Filter defined with Fold
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
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
Reading & Programming in Week 6
Reading
Sebesta Chapter 15: Functional Programming Languages
Java Script TGP Chapter 4: Functions
Week 7: Polymorphism
WebLab: C, JavaScript, Scala tutorialsGraded Assignment 1: Dynamic Dispatch in C (deadline 2 April 2013, 23:59)