Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003 CS 314, LS, LTM: Functional Programming 1
Scheme A program is an expression to be evaluated (in pure functional Scheme), not a command to be executed. An expression is: a constant: 3, 22/7, 3.1416, hello a variable that has been bound to some value: x,?a, + or a function application A function application is written as a list: (+ 3 5) parens around the list; white space separates elements the first element in the list specifies a function: + the remaining elements specify the arguments: 3, 5 CS 314, LS, LTM: Functional Programming 2
Function Application To evaluate a function application, e.g., (+ 3 5): evaluate the first element + R [machine code for addition] evalute the remaining elements 3 R 3 5 R 5 apply the value of the first to the values of the rest apply [machine code for addition] to 3, 5 R 8 This is like the mathematical concept of a function: plus(3, 5) = 8 CS 314, LS, LTM: Functional Programming 3
Function Application Function applications can be nested, e.g., (+ 5 (- 7 3)): + R [machine code for addition] 5 R 5 (- 7 3) R evaluate like any function application - R [machine code for subtraction] 7 R 7 3 R 3 apply [machine code for subtraction] to 7 and 3 R 4 apply [machine code for addition] to 5 and 4 R 9 CS 314, LS, LTM: Functional Programming 4
Function Abstraction How do we get new functions? We define them by a process called function abstraction. First, write a lambda expression: (lambda (x) (+ x x)) This expression represents a function with a formal parameter, x, and a body, (+ x x). Now apply this lambda expression to an appropriate argument, just like any other function application: ((lambda (x) (+ x x)) 4) function argument CS 314, LS, LTM: Functional Programming 5
Function Abstraction How to evaluate ((lambda (x) (+ x x)) 4)? (lambda (x) (+ x x)) R [function...] 4 R 4 apply [function...] to 4 by creating a new binding context R 8 in which x has the value 4, and then evaluating (+ x x) in this context: + R [machine code for addition] x R 4 x R 4 apply [machine code for addition] to 4 and 4 R 8 CS 314, LS, LTM: Functional Programming 6
Function Definitions If we want this new function to be available in a global context, we can give it a name at the top level : (define double (lambda (x) (+ x x))) We can then use this name in a function application: (double 4) R 8 We can abbreviate the form of a function definition: (define (double x) (+ x x)) Note: Dybvig uses the first style; Louden uses the second style. CS 314, LS, LTM: Functional Programming 7
Lists as Data (a (b c) (d)) car cdr a a ( ) b c ( ) d ( ) ( ) ( ) b c d ( ) CS 314, LS, LTM: Functional Programming 8
Improper Lists (a. b) a b a b (a b. c) a a b c b c CS 314, LS, LTM: Functional Programming 9
Lists as Data <datum> ::= <number> <symbol> <list> <list> ::= ( <datum> [ { <datum> } ]. <datum> ) ( { <datum> } ) (a (b c) (d)) is a list ( ) is the empty list (b c) is a proper list (a. b) is an improper list, also called a dotted pair (a b. c) is an improper list a b c ( ) d ( ) ( ) CS 314, LS, LTM: Functional Programming 10
Operations on Lists Basic Functions: (car list) returns the first element of list (cdr list) returns the rest of list (cons element list) constructs a new list by adding element to the front of list (null? list) returns #t if list is empty, otherwise it returns #f (quote (a b c)) or (a b c) is a special form that quotes its arguments without evaluation. CS 314, LS, LTM: Functional Programming 11
Operations on Lists Examples: (car (a b c)) R a (car ((a) b (c d))) R (a) (cdr (a b c)) R (b c) (cdr ((a) b (c d))) R (b (c d)) (cons (a b c) ((a) b (c d))) R ((a b c) (a) b (c d)) (cons d (e)) R (d e) (cons (a b) (c d)) R ((a b) c d) a ( ) b c d ( ) ( ) ((a) b (c d)) CS 314, LS, LTM: Functional Programming 12
Conditional Execution (if <test> <consequent> <alternative>) evaluate <test> if result is a true value (i.e., anything but #f), then evaluate and return <consequent> otherwise, evaluate and return <alternative> (cond (<test> <expr1> <expr2>...) (<test> <expr1> <expr2>...)... (else <expr1> <expr2>...)) CS 314, LS, LTM: Functional Programming 13
Read-Eval Eval-Print Loop Read input from user A function (or symbol) definition A function application Evaluate input Store function (or symbol) definition Evaluate function application Print return value The name of the function (or symbol) being defined The value of the function application CS 314, LS, LTM: Functional Programming 14
Pure Functional Programming Properties: The result of a function application is independent of the context in which it occurs (referential transparency). Variables are bound to values only through the linking of actual parameters to formal parameters in function calls (no side effects). Control flow is governed by function calls and conditional expressions (and recursion). Storage management is implicit (and requires garbage collection). Functions are first class citizens! CS 314, LS, LTM: Functional Programming 15
Pure Functional Programming Look, Ma, No Hands! No assignment statements! No iteration! How is it possible to write programs in a language like this? Some Simple Examples: append length flatten atomcount CS 314, LS, LTM: Functional Programming 16
Equality > (define (f x y) (list x y)) > (f a a) What happens? x > (f (a) (a)) What happens? the atom: a y x a the arguments: (a) y a ( ) CS 314, LS, LTM: Functional Programming 17
Equality eq? checks atoms for equal values but doesn t work correctly on lists eql? equality function for lists (define (eql? x y) (or (and (atom? x) (atom? y) (eq? x y)) (and (pair? x) (pair? y) (eql? (car x) (car y)) (eql? (cdr x) (cdr y))))) CS 314, LS, LTM: Functional Programming 18
Equality (eql? (a) (a)) R #t (eql? a b) R #f (eql? b b) R #t (eql? ((a)) (a)) R #f (eq? a a) R #t (eq? (a) (a)) R #f CS 314, LS, LTM: Functional Programming 19
Tail Recursion (define (memq e list) (cond ((null? list) #f) ((eq? (car list) e) list) (else (memq e (cdr list))))) Note: The last thing this function does is a recursive call. This is good, because: The compiler can optimize the call by removing the explicit recursion. The complexity of the algorithm can often be improved by writing the function in a tail-recursive form. CS 314, LS, LTM: Functional Programming 20
Accumulators Sometimes, a function can be written in tail-recursive form by using accumulators: Two versions of factorial. Two versions of reverse: naive reverse is O(n 2 ), but reverse with an accumulator is O(n). Other examples: fibonacci flatten... CS 314, LS, LTM: Functional Programming 21
Binding Local Variables How to achieve: x := (f a) y := (g b) <expression involving x and y > A solution using lambda expressions: ((lambda (x y) <expression involving x and y >) (f a) (g b)) CS 314, LS, LTM: Functional Programming 22
Let and Let* (let ((x (f a)) (y (g b))) <expression involving x and y > ) Note: (f a) and (g b) evaluated in parallel. (let* ((x (f a)) (y (g x))) <expression involving x and y > ) Note: (f a) and (g x) evaluated sequentially, left to right. CS 314, LS, LTM: Functional Programming 23
Let and Let* (let ((f (lambda (x) (+ x x))) (y 3)) (f y)) R 6 (let* ((f (lambda (x) (+ x x))) (g (lambda (x) (* 2 (f x)))) (y 3)) (g y)) R 12 CS 314, LS, LTM: Functional Programming 24
Functions: First-Class Objects Functions as arguments: > (define (f g x) (g (car x))) (f number? (0 a)) R #t (f length ((2 3) (4))) R 2 (f (lambda (x) (* 2 x)) (3)) R 6 Functions as return values: > (define (incr) (lambda (n) (+ 1 n))) ((incr) 4) R 5 CS 314, LS, LTM: Functional Programming 25
Higher Order Functions (apply <function> <arguments>) apply <function> to list of <arguments> (apply + (1 2 3)) R 6 (apply zero? '(2)) R #f (apply (lambda (n) (+ 1 n)) (3)) R 4 (eval <expression>) evaluate <expression> as a function application (eval (+ 3 4)) R 7 (eval (list + 3 4)) R 7 CS 314, LS, LTM: Functional Programming 26
Higher Order Functions Examples: (map <function> <list>) apply <function> to the elements of <list> example: use map to redefine atomcount (foldright <operation> <list> <identity>) use associative binary <operation> to fold up <list> examples: foldright used with + and append By composing higher order functions we can construct powerful new functions! CS 314, LS, LTM: Functional Programming 27