Forward recursion. CS 321 Programming Languages. Functions calls and the stack. Functions calls and the stack

Similar documents
CS 321 Programming Languages

Forward Recursion. Programming Languages and Compilers (CS 421) Mapping Recursion. Forward Recursion: Examples. Folding Recursion.

Booleans (aka Truth Values) Programming Languages and Compilers (CS 421) Booleans and Short-Circuit Evaluation. Tuples as Values.

# true;; - : bool = true. # false;; - : bool = false 9/10/ // = {s (5, "hi", 3.2), c 4, a 1, b 5} 9/10/2017 4

Programming Languages and Compilers (CS 421)

Programming Languages and Compilers (CS 421)

n What is its running time? 9/18/17 2 n poor_rev [1,2,3] = n (poor_rev [1] = n ((poor_rev [1] =

Topic 5: Examples and higher-order functions

CSc 520. Gofer III. Accumulative Recursion. Accumulative Recursion... Stack Recursion. Principles of Programming Languages. Christian Collberg

CSE341: Programming Languages Lecture 6 Nested Patterns Exceptions Tail Recursion. Zach Tatlock Winter 2018

Functions Over Lists. Programming Languages and Compilers (CS 421) Structural Recursion. Functions Over Lists. Structural Recursion : List Example

COSE212: Programming Languages. Lecture 4 Recursive and Higher-Order Programming

CS Lecture 6: Map and Fold. Prof. Clarkson Spring Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CS Lecture 6: Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

Tail Recursion. ;; a recursive program for factorial (define fact (lambda (m) ;; m is non-negative (if (= m 0) 1 (* m (fact (- m 1))))))

FUNCTIONAL PROGRAMMING

Recursion. What is Recursion? Simple Example. Repeatedly Reduce the Problem Into Smaller Problems to Solve the Big Problem

Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Functional Programming. Overview. Topics. Definition n-th Fibonacci Number. Graph

Continuations and Continuation-Passing Style

CSE 341 Lecture 5. efficiency issues; tail recursion; print Ullman ; 4.1. slides created by Marty Stepp

CSC324- TUTORIAL 5. Shems Saleh* *Some slides inspired by/based on Afsaneh Fazly s slides

PROGRAMMING IN HASKELL. CS Chapter 6 - Recursive Functions

Tail Recursion and Accumulators

List Functions, and Higher-Order Functions

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

CS 11 Ocaml track: lecture 2

Function Calling Conventions 2 CS 64: Computer Organization and Design Logic Lecture #10

Data Structures And Algorithms

OVERVIEW. Recursion is an algorithmic technique where a function calls itself directly or indirectly. Why learn recursion?

Ozyegin University CS 321 Programming Languages Sample Problems 05

CS1 Recitation. Week 2

Two Approaches to Algorithms An Example (1) Iteration (2) Recursion

MoreIntro_annotated.v. MoreIntro_annotated.v. Printed by Zach Tatlock. Oct 04, 16 21:55 Page 1/10

Logic and Computation Lecture 20 CSU 290 Spring 2009 (Pucella) Thursday, Mar 12, 2009

Names and Functions. Chapter 2

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

CSci 4223 Principles of Programming Languages

Functions and the MIPS Calling Convention 2 CS 64: Computer Organization and Design Logic Lecture #11

Python review. 1 Python basics. References. CS 234 Naomi Nishimura

Attributes of Variable. Lecture 13: Run-Time Storage Management. Lifetime. Value & Location

Software Analysis. Asymptotic Performance Analysis

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

CSCI 2041: Tail Recursion and Activation Records

CSE 413 Midterm, May 6, 2011 Sample Solution Page 1 of 8

Lecture 35: Analysis Review & Tail Recursion 10:00 AM, Nov 28, 2018

Functional Programming. Pure Functional Programming

Recursion & Iteration

A brief tour of history

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

Compiler Construction Lecture 05 A Simple Stack Machine. Lent Term, Lecturer: Timothy G. Griffin. Computer Laboratory University of Cambridge

CS 310 Advanced Data Structures and Algorithms

Option Values, Arrays, Sequences, and Lazy Evaluation

Programovací jazyky F# a OCaml. Chapter 5. Hiding recursion using function-as-values

CS 4110 Programming Languages & Logics. Lecture 35 Typed Assembly Language

Programming Languages and Techniques (CIS120)

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Today s Plan. Programming Languages. Example : Factorial. Recursion. CSE 130 : Spring Lecture 6: Higher-Order Functions

The Art of Recursion: Problem Set 10

Functional Programming. Pure Functional Programming

RECURSION. Problem Solving with Computers-II 6

Exercises on ML. Programming Languages. Chanseok Oh

Week 5 Tutorial Structural Induction

Tuples. CMSC 330: Organization of Programming Languages. Examples With Tuples. Another Example

RECURSION, RECURSION, (TREE) RECURSION! 2

Algorithmics. Some information. Programming details: Ruby desuka?

Problem Set CVO 103, Spring 2018

CS558 Programming Languages

O(1) How long does a function take to run? CS61A Lecture 6

Unit #2: Recursion, Induction, and Loop Invariants

Unit #3: Recursion, Induction, and Loop Invariants

Parsing Scheme (+ (* 2 3) 1) * 1

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

CSCI-GA Scripting Languages

CS 216 Fall 2007 Final Exam Page 1 of 10 Name: ID:

CS Prof. Clarkson Fall 2014

CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees. CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees 1

Programming Languages. Streams Wrapup, Memoization, Type Systems, and Some Monty Python

Spring 2012 Homework 10

Lecture 10: Recursion vs Iteration

Tail Calls. CMSC 330: Organization of Programming Languages. Tail Recursion. Tail Recursion (cont d) Names and Binding. Tail Recursion (cont d)

CS/ENGRD 2110 Object-Oriented Programming and Data Structures Spring 2012 Thorsten Joachims. Lecture 10: Asymptotic Complexity and

COMP 401 Fall Recitation 7: Factories and Lists

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

CMSC 330, Fall 2013, Practice Problems 3

CSE 130 [Winter 2014] Programming Languages

Halting Measures and Termination Arguments

Code Generation. Lecture 12

CSE 341 : Programming Languages Midterm, Spring 2015

CS113: Lecture 4. Topics: Functions. Function Activation Records

CS61A Lecture 7 Complexity and Orders of Growth. Jon Kotker and Tom Magrino UC Berkeley EECS June 27, 2012

Lists. Michael P. Fourman. February 2, 2010

Recursion. February 02, 2018 Cinda Heeren / Geoffrey Tien 1

Interpreters and Tail Calls Fall 2017 Discussion 8: November 1, 2017 Solutions. 1 Calculator. calc> (+ 2 2) 4

Informatics 1 Functional Programming Lecture 4. Lists and Recursion. Don Sannella University of Edinburgh

Using the MIPS Calling Convention. Recursive Functions in Assembly. CS 64: Computer Organization and Design Logic Lecture #10 Fall 2018

Lecture: Functional Programming

COMPUTER SCIENCE IN THE NEWS. CS61A Lecture 7 Complexity and Orders of Growth TODAY PROBLEM SOLVING: ALGORITHMS COMPARISON OF ALGORITHMS 7/10/2012

CSCI-GA Final Exam

Transcription:

Forward recursion CS 321 Programming Languages Intro to OCaml Recursion (tail vs forward) Baris Aktemur Özyeğin University Last update made on Thursday 12 th October, 2017 at 11:25. Much of the contents here are taken from Elsa Gunter and Sam Kamin s OCaml notes available at http://courses.engr.illinois.edu/cs421 In forward recursion, you first call the function recursively on all the recursive components, and then build the final result from the partial results. Wait until the whole structure has been traversed to start building the answer. # let rec tally lst = [] -> 0 x::xs -> x + tally xs;; # let rec squareup lst = [] -> [] x::xs -> (x*x)::squareup xs;; Özyeğin University CS 321 Programming Languages 1 Özyeğin University CS 321 Programming Languages 2 tally [2;6;8]

tally [6;8] tally [2;6;8] tally [8] tally [6;8] tally [2;6;8] tally [] tally [8] tally [6;8] tally [2;6;8] tally [] 0 tally [8] tally [6;8] tally [2;6;8]

tally [8] 8+0 tally [6;8] tally [2;6;8] tally [6;8] 6+8 tally [2;6;8] tally [2;6;8] 2+14 4+16

Tail recursion A recursive function is tail-recursive if all recursive calls are the last thing that the function does. Tail recursion generally requires extra accumulator arguments to pass partial results. May require an auxiliary function. 20 # let rec tally lst acc = [] -> acc x::xs -> tally xs (x+acc);; val tally : a list -> int -> int # tally [1;2;3;4;5] 0;; (* Have to give an initial accumulated value *) val it : int = 15 Özyeğin University CS 321 Programming Languages 4

tally [6;8] 6 tally [8] 12 tally [6;8] 6 tally [] 20 tally [8] 12 tally [6;8] 6 tally [] 20 20 tally [8] 12 tally [6;8] 6

tally [8] 12 20 tally [6;8] 6 tally [6;8] 6 20 20 20

An optimization idea Observation When we have tail recursion, a function that is waiting for the called function to return a value simply propagates the return value to its caller. 20 Idea We don t need to keep the frame of a tail-recursive function on the stack. Simply replace the tail-recursive function s stack frame with the called function. Özyeğin University CS 321 Programming Languages 6 Özyeğin University CS 321 Programming Languages 7 Özyeğin University CS 321 Programming Languages 8

tally [6;8] 6 tally [8] 12 Özyeğin University CS 321 Programming Languages 9 Özyeğin University CS 321 Programming Languages 10 tally [] 20 tally [] 20 20 Özyeğin University CS 321 Programming Languages 11 Özyeğin University CS 321 Programming Languages 11

Why do we care? 20 Reusing the stack frame of the tail-recursive function is known as the tail call optimization. It is an automatic optimization applied by the compilers and interpreters. Özyeğin University CS 321 Programming Languages 12 Özyeğin University CS 321 Programming Languages 13 Experiment Experiment Write a function that takes a value x and an integer n, and returns a list of length n whose elements are all x. # let rec makelist x n = Write a function that takes a value x and an integer n, and returns a list of length n whose elements are all x. # let rec makelist x n = if n = 0 then [] else x :: makelist x (n-1);; val makelist : a -> int -> a list = <fun> # makelist "a" 5;; - : string list = ["a"; "a"; "a"; "a"; "a"] # makelist 3 40;; - : int list = [3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3] val makelist : a -> int -> a list = <fun> # makelist "a" 5;; - : string list = ["a"; "a"; "a"; "a"; "a"] # makelist 3 40;; - : int list = [3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3] Özyeğin University CS 321 Programming Languages 14 Özyeğin University CS 321 Programming Languages 14

Experiment Experiment # let rec makelist x n acc = if n = 0 then acc else makelist x (n-1) (x::acc);; # makelist 3 99999;; - : int list = [3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3;...] # makelist 3 1234567;; Stack overflow during evaluation (looping recursion?). val makelist : a -> int -> a list -> a list = <fun> # makelist 3 10 [];; - : int list = [3; 3; 3; 3; 3; 3; 3; 3; 3; 3] # makelist 3 12345678 [];; - : int list = [3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3; 3...] Observation Hmm... So there really is a difference between tail vs. forward recursion. Özyeğin University CS 321 Programming Languages 15 Özyeğin University CS 321 Programming Languages 16 How to write tail-recursive functions? Tail recursion To write functions in tail-recursive form, answer the following question: What information do I need to pass from the caller to the callee (i.e. from a lower stack frame to the upper stack frame) so that I won t need the caller again, and can simply throw it away? # let rec squareup lst = [] -> [] x::xs -> (x*x)::squareup xs;; val squareup : int list -> int list = <fun> # let rec squareup lst acc = [] -> acc x::xs -> squareup xs (acc@[x*x]);; val squareup : int list -> int list -> int list = <fun> # squareup [1;2;3;4;5] [];; - : int list = [1; 4; 9; 16; 25] Özyeğin University CS 321 Programming Languages 17 Özyeğin University CS 321 Programming Languages 18

Exercise Exercise solutions Convert the following functions to tail-recursive form. # let rec factorial n = if n = 0 then 1 else n * factorial (n - 1);; # let rec power x n = if n = 0 then 1 else x * power x (n - 1);; # let rec fib n = if n = 0 then 1 else if n = 1 then 1 else fib(n-1) + fib(n-2);; # let rec factorial n acc = if n = 0 then acc else factorial (n-1) (n*acc);; val factorial : int -> int -> int # factorial 0 1;; - : int = 1 # factorial 1 1;; - : int = 1 # factorial 5 1;; - : int = 120 # factorial 6 1;; - : int = 720 Özyeğin University CS 321 Programming Languages 19 Özyeğin University CS 321 Programming Languages 20 Exercise solutions Better Programming # let rec fib n nm1 nm2 = if n = 0 then nm2 else if n = 1 then nm1 else fib (n-1) (nm1+nm2) nm1;; val fib : int -> int -> int -> int = <fun> # fib 0 1 1;; (* Initial values for nm1 and nm2 are 1 and 1 *) - : int = 1 # fib 1 1 1;; - : int = 1 # fib 2 1 1;; - : int = 2 # fib 3 1 1;; - : int = 3 # fib 4 1 1;; - : int = 5 # fib 5 1 1;; - : int = 8 # fib 6 1 1;; - : int = 13 Özyeğin University CS 321 Programming Languages 21 Use an auxiliary function to hide the accumulator from the user. # let tally numbers = let rec sum lst acc = [] -> acc x::xs -> sum xs (x+acc) in sum numbers 0;; val tally : int list -> int = <fun> # let squareup numbers = let rec aux lst acc = [] -> acc x::xs -> aux xs (acc@[x*x]) in aux numbers [];; val squareup : int list -> int list = <fun> Özyeğin University CS 321 Programming Languages 22

Better Programming Exercise Convert the following function to tail-recursive form. Use an auxiliary function to hide the accumulator from the user. # let factorial n = let rec fact m acc = if m = 0 then acc else fact (m-1) (m*acc) in fact n 1;; val factorial : int -> int = <fun> # let fib m = let rec aux n nm1 nm2 = if n = 0 then nm2 else if n = 1 then nm1 else aux (n-1) (nm1 + nm2) nm1 in aux m 1 1;; val fib : int -> int = <fun> # let rec rev alist = match alist with [] -> [] x::xs -> rev xs @ [x];; val rev : a list -> a list = <fun> # rev [1;2;3;4;5;6];; - : int list = [6; 5; 4; 3; 2; 1] Özyeğin University CS 321 Programming Languages 23 Özyeğin University CS 321 Programming Languages 24 Exercise Tail vs. Forward Convert the following function to tail-recursive form. # let rec rev alist = match alist with [] -> [] x::xs -> rev xs @ [x];; val rev : a list -> a list = <fun> # rev [1;2;3;4;5;6];; - : int list = [6; 5; 4; 3; 2; 1] # let rev alist = let rec aux lst acc = [] -> acc x::xs -> rev xs (x::acc) in aux alist [];; val rev : a list -> a list = <fun> Note: In general, it is possible for a recursion to be neither forward nor tail. This is the case when a function does some stuff, makes the recursive call, then further processes the return value of the recursive call. For simplicity and without loss of the point we are making in this lecture, we consider only forward vs. tail recursion. Özyeğin University CS 321 Programming Languages 24 Özyeğin University CS 321 Programming Languages 25

Exercise How long will it take? Convert the following function to tail-recursive form. # let rec numzeros lst = [] -> 0 0::xs -> 1 + numzeros xs x::xs -> numzeros xs;; Remember the big-oh notation from CS201? Question: given input of size n, how long to generate output? Express output time in terms of input size, omit constants and take the biggest power. Özyeğin University CS 321 Programming Languages 26 Özyeğin University CS 321 Programming Languages 27 Common big-o times Linear time Constant time O(1) input size doesn t matter Linear time O(n) double input = double time Quadratic time O(n 2 ) double input = quadruple time Exponential time O(2 n ) increment input = double time Expect most list operations to take linear time O(n). Each step of the recursion can be done in constant time. Each step makes only one recursive call. List example: length, squareup, append Integer example: factorial # let rec length lst = [] -> 0 x::xs -> 1 + length xs;; Özyeğin University CS 321 Programming Languages 28 Özyeğin University CS 321 Programming Languages 29

Quadratic time Comparison Each step of the recursion takes time proportional to input Each step of the recursion makes only one recursive call. List example: let rec poorrev lst = [] -> [] x::xs -> poorrev xs @ [x];; (* Compare poorrev to the function below *) let rec rev_aux lst acc = [] -> acc x::xs -> rev_aux xs (x::acc);; poorrev [1;2;3] = (poorrev [2;3])@[1] = ((poorrev[3])@[2])@[1] = (((poorrev[])@[3])@[2])@[1] = (([]@[3])@[2])@[1] = ([3]@[2])@[1] = (* append is linear *) (3::([]@[2]))@[1] = [3;2]@[1] = 3::([2]@[1]) = 3::(2::([]@[1])) = [3;2;1] let rev lst = rev_aux lst [];; 0 1 Comparison Exponential time rev [1;2;3] = rev_aux [1;2;3] [] = rev_aux [2;3] [1] = rev_aux [3] [2;1] = rev_aux [] [3;2;1] = [3;2;1] Hideous running times on input of any size Each step of recursion takes constant time Each recursion makes two recursive calls Easy to write naive code that is exponential for functions that can be linear 2 3

Exponential time let rec naivefib n = match n with 0 -> 1 1 -> 1 _ -> naivefib (n-1) + naivefib (n-2);; let fib n = let rec tailfib n nm1 nm2 = if n = 0 then nm2 else if n = 1 then nm1 else tailfib (n-1) (nm1+nm2) nm1 in tailfib n 1 1;; Experiment Run the two versions with various big inputs. (e.g. 40) What difference do you see? 4