SLIDE 1
Looking back Write one thing you learned about higher-order and - - PowerPoint PPT Presentation
Looking back Write one thing you learned about higher-order and - - PowerPoint PPT Presentation
Looking back Write one thing you learned about higher-order and anonymous functions. Your answers may be anonymously shared with your classmates. Reflection Consider the following algebraic laws for list reversal: reverse () = ()
SLIDE 2
SLIDE 3
(append (reverse (cdr xs)) (list1 (car xs))))) where list1 is a function that makes a
- ne-element list from its argument.
Answer these questions:
- For a list reversal function to be considered to
have good performance, what should its running time be in terms of the length of its argument?
- What is the running time of the reverse
function above?
SLIDE 4
Naive list reversal
(define reverse (xs) (if (null? xs) ’() (append (reverse (cdr xs)) (list1 (car xs)))))
SLIDE 5
Tail calls
Intuition: In a function, a call is in tail position if it is the last thing the function does.
(define reverse (xs) (if (null? xs) ’() (append (reverse (cdr xs)) (list1 (car xs)))))
SLIDE 6
Tail calls
Intuition: In a function, a call is in tail position if it is the last thing the function does.
(define reverse (xs) (if (null? xs) ’() (append (reverse (cdr xs)) (list1 (car xs)))))
A tail call is a call in tail position.
SLIDE 7
What is tail position?
Tail position is defined inductively:
- The body of a function is in tail position
- When (if e1 e2 e3) is in tail position, so are
e2 and e3
- When (let (...) e) is in tail position, so is e,
and similary for letrec and let*.
- When (begin e1 ... en) is in tail position, so
is en. Idea: The last thing that happens
SLIDE 8
Check your understanding: Tail Position
Consider the following code
- > (define foldr (plus zero xs)
(if (null? xs) zero (plus (car xs) (foldr plus zero (cdr xs))))) Now answer the following questions. The occurrence of expression zero in the true-branch of the if expression is in tail position.
- True
- False
Answer: True. The body of the function is in tail
SLIDE 9
position, which makes the if expression itself in tail position. The rule for if is that the true and false branches share the tail status of the if expression, so zero is in tail position. The occurrence of expression plus in the false-branch of the if expression is in tail position.
- True
- False
Answer: True. The body of the function is in tail position, which makes the if expression itself in tail position. The rule for if is that the true and false branches share the tail status of the if
- expression. The call to plus is the last thing in the
SLIDE 10
false-branch, so it is in tail position. The occurrence of expression foldr in the false-branch of the if expression is in tail position.
- True
- False
Answer: False. The call to foldr is within the call to plus in the false-branch of the if expression, so it cannot be the last thing that happens.
SLIDE 11
Tail-call optimization & accumulating parameters
Tail-call optimization
- Anything in tail position is the last thing executed,
so its stack frame can be recycled
- Before executing a call in tail position,
abandon current stack frame
- Results in asymptotic space savings
Accumulating Parameter
- Add a parameter to accumulate answer
- Moves recursive call to tail position
SLIDE 12
Example: Accumulating reverse function
Key ideas:
- Recursive call is in a tail position
- Accumulating parameter collects answer
Contract: (revapp xs ys) = (append (reverse xs) ys) Laws: (revapp ’() ys) == ys (revapp (cons z zs) ys) == (revapp zs (cons z ys))
SLIDE 13
Reversal by accumulating parameters
; laws: (revapp ’() ys) = ys ; (revapp (cons z zs) ys) = ; (revapp zs (cons z ys)) (define revapp (xs ys) ; return (append (reverse xs) ys) (if (null? xs) ys (revapp (cdr xs) (cons (car xs) ys)))) (define reverse (xs) (revapp xs ’()))
SLIDE 14
Tail position in revapp
(define revapp (xs zs) (if (null? xs) zs (revapp (cdr xs) (cons (car xs) zs))))
SLIDE 15
Tail position in revapp
(define revapp (xs zs) (if (null? xs) zs (revapp (cdr xs) (cons (car xs) zs))))
Values xs and zs go in machine registers. Code compiles to a loop.
SLIDE 16
Check your understanding: Accumulating Parameters
An accumulating parameter to a recursive function f accumulates the answer so that a recursive call to f can be in tail position.
- True
- False
Answer: True. The stack frame of a function call that is not in tail position cannot be shared with subsequent calls because its values may still be needed.
- True
SLIDE 17
- False
Answer: True. Tail-call optimizations and the use of accumulating parameters can only result in constant-time improvements to the complexity of a function.
- True
- False
Answer: False. The revapp version of the reverse function is linear in the length of the list being reversed while the naive version of reverse is quadratic.
SLIDE 18
Reflection
Are tail calls familiar? What other programming construct
- 1. Transfers control to another point in the code?
- 2. Uses no stack space?
SLIDE 19
Tail calls as gotos with arguments
Gotos
- Transfer control to another point in the code
- Use no stack space
- Can only go to code marked with labels
Tail calls
- Transfer control to another point in the code
- Use no stack space
- Can transfer control to any function
- Can take parameters!
SLIDE 20
Continuations: First-class tail calls
A continuation is code that represents “the rest of the computation.”
- Not a normal function call because
continuations never return
- Think “goto with arguments”
Context: an advanced technique, heavily used in event-driven programming:
- GUIs, games, web, embedded devices
SLIDE 21
Different coding styles
Direct style
- Last action of a function is to return a value.
(This style is what you are used to.) Continuation-passing style (CPS)
- Last action of a function is to “throw” answer to
a continuation. (For us, tail call to a parameter.)
SLIDE 22
Uses of continuations
- Compiler representation:
– Compilers for functional languages often convert direct-style user code to CPS because CPS matches control-flow of assembly.
- First-class continuations.
– Some languages provide a construct for capturing the current continuation and giving it a name k. – Control can be resumed at captured continuation by throwing to k.
- A style of coding that can mimic exceptions
- Callbacks in GUI frameworks and web services
- Event loops in game programming and other concurrent
settings
SLIDE 23
Implementation
- We’re going to simulate continuations with
function calls in tail position.
- First-class continuations require compiler
support. – primitive function that materializes “current continuation” into a variable.
SLIDE 24
Check your understanding: Continuation Introduction
A continuation is different from a normal function because it never returns to the context from which it was invoked.
- True
- False
Answer: True. Continuations cannot take arguments.
- True
- False
Answer:False.
SLIDE 25
Continuations are used in GUI frameworks and to mimic exceptions.
- True
- False
Answer: True.
SLIDE 26
Reflection
Consider the following algebraic laws for a witness function: (witness p? xs) == x, where (member x xs), provided (exists? p? xs) Now answer this questions:
- What should the function do if there exists no
such x?
SLIDE 27
Design Problem: Missing Value
Provide a witness to existence: (witness p? xs) == x, where (member x xs), provided (exists? p? xs) Problem: What if there exists no such x? Bad ideas:
- nil
- special symbol fail
- run-time error
Good idea: exception (but not available in uScheme)
SLIDE 28
Solution: A New Interface
Success and failure continuations! Contract written using properties (not algorithmic) (witness-cps p? xs succ fail) = (succ x) ; where x is in xs and (p? x) (witness-cps p? xs succ fail) = (fail) ; where (not (exists? p? xs))
SLIDE 29
From contract to laws
(witness-cps p? xs succ fail) = (succ x) ; where x is in xs and (p? x) (witness-cps p? xs succ fail) = (fail) ; where (not (exists? p? xs))
Where do we have forms of data?
(witness-cps p? ’() succ fail) = ? (witness-cps p? (cons z zs) succ fail) = ? ; when (p? z) (witness-cps p? (cons z zs) succ fail) = ? ; when (not (p? z))
SLIDE 30
Coding witness with continuations
(define witness-cps (p? xs succ fail) (if (null? xs) (fail) (let ([z (car xs)]) (if (p? z) (succ z) (witness-cps p? (cdr xs) succ fail)))))
SLIDE 31
“Continuation-Passing Style” by laws
The right-hand side of every law calls a parameter (witness-cps p? xs succ fail) = (succ x) ; where x is in xs and (p? x) (witness-cps p? xs succ fail) = (fail) ; where (not (exists? p? xs))
SLIDE 32
“Continuation-Passing Style” by code
All tail positions are continuations or recursive calls
(define witness-cps (p? xs succ fail) (if (null? xs) (fail) (let ([z (car xs)]) (if (p? z) (succ z) (witness-cps p? (cdr xs) succ fail)))))
Compiles to tight code
SLIDE 33
Example Use: Instructor Lookup
- > (val 2020f ’((Fisher 105)(Monroe 40)(Chow 116)))
- > (instructor-info ’Fisher 2020f)
(Fisher teaches 105)
- > (instructor-info ’Chow 2020f)
(Chow teaches 116)
- > (instructor-info ’Votipka 2020f)
(Votipka is-not-on-the-list)
SLIDE 34
Instructor Lookup: The Code
; info has form: ’(Fisher 105) ; classes has form: ’(info_1
- info_n)
(define instructor-info (instructor classes) (let ( [s (lambda (info) ; success continuation (list3 instructor ’teaches (cadr info)))] [f (lambda () ; failure continuation (list2 instructor ’is-not-on-the-list))]) (witness-cps pred classes s f))
SLIDE 35
Instructor Lookup: The Code
; info has form: ’(Fisher 105) ; classes has form: ’(info_1
- info_n)
(define instructor-info (instructor classes) (let ( [s (lambda (info) ; success continuation (list3 instructor ’teaches (cadr info)))] [f (lambda () ; failure continuation (list2 instructor ’is-not-on-the-list))]) (witness-cps (o ((curry =) instructor) car) classes s f))
SLIDE 36
Instructor Lookup: The Code
; info has form: ’(Fisher 105) ; classes has form: ’(info_1
- info_n)
(define instructor-info (instructor classes) (let ( [s (lambda (info) ; success continuation (list3 instructor ’teaches (cadr info)))] [f (lambda () ; failure continuation (list2 instructor ’is-not-on-the-list))]) (witness-cps (o ((curry =) instructor) car) classes s f))
SLIDE 37
Instructor Lookup: The Code
; info has form: ’(Fisher 105) ; classes has form: ’(info_1
- info_n)
(define instructor-info (instructor classes) (let ( [s (lambda (info) ; success continuation (list3 instructor ’teaches (cadr info)))] [f (lambda () ; failure continuation (list2 instructor ’is-not-on-the-list))]) (witness-cps (o ((curry =) instructor) car) classes s f)))
SLIDE 38
Coding Interlude: witness-cps
Consider the following code: (define witness-cps (p? xs succ fail) (if (null? xs) (fail) (let ([z (car xs)]) (if (p? z) (succ z) (witness-cps p? (cdr xs) succ fail))))) (val 2020f ’((Fisher 105)(Monroe 40)(Chow 116)))
SLIDE 39
(define instructor-info (instructor classes) (let ( [s (lambda (info) ; success continuation (list3 instructor ’teaches (cadr [f (lambda () ; failure continuation (list2 instructor ’is-not-on-the-list))]) (witness-cps (o ((curry =) instructor) car) classes s f))) (instructor-info ’Fisher 2020f) (instructor-info ’Chow 2020f) (instructor-info ’Votipka 2020f) Modify the code to add another professor and
SLIDE 40