Class 11: Two-argument recursion

Slides:



Advertisements
Similar presentations
Higher-Order Functions and Loops c. Kathi Fisler,
Advertisements

Lists CS 5010 Program Design Paradigms “Bootcamp” Lesson 4.1 TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: AAA 1 ©
Six compound procedures and higher-order procedures.
16-Jun-15 Recursion. 2 Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example:
Recursion. Objectives At the conclusion of this lesson, students should be able to Explain what recursion is Design and write functions that use recursion.
>(setf oldlist ) Constructing a list We know how to make a list in lisp; we simply write it: ‘4321( ) What if we want a new list with that list as a part?
CS 330 Programming Languages 11 / 20 / 2007 Instructor: Michael Eckmann.
CS 3 Final Review Gilbert Chou, Jenny Franco and Colleen Lewis December 14, pm GPB.
Midterm Logistics Where? 2050 VLSB When? Monday, 4:10 to 5:40 What to do? –“Review problems” from Thursday/Friday in UCWise. –Two practice exams and solutions.
28-Jun-15 Recursion. 2 Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example:
Rewriting your function using map and foldr CS 5010 Program Design Paradigms “Bootcamp” Lesson 5.5 TexPoint fonts used in EMF. Read the TexPoint manual.
Recursion. Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example: A list.
Introducing General Recursion CS 5010 Program Design Paradigms “Bootcamp” Lesson 8.2 TexPoint fonts used in EMF. Read the TexPoint manual before you delete.
Foldr CS 5010 Program Design Paradigms “Bootcamp” Lesson 5.4 TexPoint fonts used in EMF. Read the TexPoint manual before you delete this box.: AAA © Mitchell.
COSC 2006 Data Structures I Recursion II
CS 152: Programming Language Paradigms February 17 Class Meeting Department of Computer Science San Jose State University Spring 2014 Instructor: Ron Mak.
Recursion Recursion Chapter 12. Outline n What is recursion n Recursive algorithms with simple variables n Recursion and the run-time stack n Recursion.
Generalizing Similar Functions CS 5010 Program Design Paradigms “Bootcamp” Lesson 5.1 TexPoint fonts used in EMF. Read the TexPoint manual before you delete.
CS CS1321: Introduction to Programming Georgia Institute of Technology College of Computing Lecture 10 Sept 25th, 2001 Fall Semester.
Rewriting your function using map and foldr CS 5010 Program Design Paradigms “Bootcamp” Lesson TexPoint fonts used in EMF. Read the TexPoint manual.
The 8-queens problem CS 5010 Program Design Paradigms “Bootcamp” Lesson TexPoint fonts used in EMF. Read the TexPoint manual before you delete this.
Introducing General Recursion CS 5010 Program Design Paradigms “Bootcamp” Lesson TexPoint fonts used in EMF. Read the TexPoint manual before you.
Halting Measures and Termination Arguments CS 5010 Program Design Paradigms “Bootcamp” Lesson TexPoint fonts used in EMF. Read the TexPoint manual.
Using the List Template CS 5010 Program Design Paradigms “Bootcamp” Lesson TexPoint fonts used in EMF. Read the TexPoint manual before you delete.
Using the List Template CS 5010 Program Design Paradigms “Bootcamp” Lesson 4.2 TexPoint fonts used in EMF. Read the TexPoint manual before you delete this.
Sometimes Structural Recursion Isn't Enough CS 5010 Program Design Paradigms “Bootcamp” Lesson 8.1 TexPoint fonts used in EMF. Read the TexPoint manual.
Recursion ITI 1121 N. El Kadri. Reminders about recursion In your 1 st CS course (or its equivalent), you have seen how to use recursion to solve numerical.
Recursion. Definitions I A recursive definition is a definition in which the thing being defined occurs as part of its own definition Example: A list.
Computer Eng. Software Lab II , Semester 2, Who I am: Andrew Davison CoE, WiG Lab Office Functional Programming.
Solving Your Problem by Generalization CS 5010 Program Design Paradigms “Bootcamp” Lesson © Mitchell Wand, This work is licensed under.
Recursion. Objectives At the conclusion of this lesson, students should be able to Explain what recursion is Design and write functions that use recursion.
Function Parameters and Overloading Version 1.0. Topics Call-by-value Call-by-reference Call-by-address Constant parameters Function overloading Default.
Recursion Powerful Tool
Recursion.
Lets and Loops Tail Recursion.
Recursion Version 1.0.
Generalizing Similar Functions
Edited by Original material by Eric Grimson
CS 550 Programming Languages Jeremy Johnson
More About Recursive Data Types
CS 1321.
EGR 2261 Unit 4 Control Structures I: Selection
Debugging and Random Numbers
Halting Functions for Tree-Like Structures
CS 5010 Program Design Paradigms “Bootcamp” Lesson 4.1
CS 5010 Program Design Paradigms “Bootcamp” Lesson 5.3
Expanded Recursive Diagrams OCAML rapid tour, day 2
Chapter 5 Conclusion CIS 61.
review, let and lambda, trees?, tree-recursion?, OCAML intro
CS 270 Math Foundations of CS Jeremy Johnson
32: Games 3 Functional Data
review combinatorics bignum OCAML rapid tour, day 3
Stack Data Structure, Reverse Polish Notation, Homework 7
Lesson 2: Building Blocks of Programming
Sequential circuit design
The Metacircular Evaluator
Introduction to Computer Programming
Solving Your Problem by Generalization
Rules of evaluation The value of a number is itself.
Basics of Recursion Programming with Recursion
Mutators for compound data Stack Queue
List and list operations (continue).
Stacks Chapter 5.
Lecture # , , , , מבוא מורחב.
ormap, andmap, and filter
Generalizing Similar Functions
Rewriting your function using map and foldr
Lisp.
More Scheme CS 331.
CS 5010 Program Design Paradigms “Bootcamp” Lesson 4.1
Presentation transcript:

Class 11: Two-argument recursion Almost every procedure today will work on int-lists An int-list is either empty, or (cons item lst), where item is an int and lst is an int-list. Nothing else is an int-list. [Now we don't need to do that part of the design recipe] Examples (define ex0 empty) (define ex1 (list 1 3)) (define ex2 (list 1 4 7)) (define ex3 (list 2 4 9)) Most procedures will use two arguments

Warmup: two argument recursion, list + atomic We wrote "improve", which converted (list 3 7 10) to (list 17 17 17) Recursive diagram: Orig. in.: (list 3 7 10) Rec. In: (list 7 10) Rec. out: (list 17 17) Cons on a 17 to the recursive output? Orig out (list 17 17 17)

Warmup: two argument recursion, list + atomic We wrote "improve", which converted (list 3 7 10) to (list 17 17 17) Code: (define (improve aloi) (cond [(empty? aloi) empty] [(cons? aloi) (cons 17 (improve (rest aloi)))]))

New: (better num aloi) Better produces a new list of the same length as aloi, but with each item replaced with "num: (better (list 3 7 10) 14) produces (list 14 14 14) Recursive diagram: Orig. in.: (list 3 7 10), 14 Rec. In: (list 7 10), 14 Rec. out: (list 14 14) Cons on a "num" to the recursive output? Orig out: (list 14 14 14)

New: (better num aloi) Better produces a new list of the same length as aloi, but with each item replaced with "num: code (define (better num aloi) (cond [(empty? aloi) empty] [(cons? aloi) (cons num (better (rest aloi)))]))

General rules for natural num* list recursion Recursive input is often the same natnum, and "rest" of the list Alternatives: reduce natnum by 1, keep the list the same; base case is when natnum is zero reduce natnum by 1, take "rest" of the list. reduce natnum by 1, somehow enlarge this list … Example of case 2: to find the nth item in a list (of at least n items)… find the n-1st item in the rest of the list! This weekend's lab: natural-number recursion

Generalities More arguments means more complexity More arguments means more things you might recur on…and just about any possibility might arise. More arguments means more structures in the main "cond": empty, empty cons, empty empty, cons cons, cons For two-list recursion, three main possibilities Illustrate one with a first example: all-matches

Example proc: "all-matches" ; all-matches: (int list) * (int list) -> (int list) ; Input: lists aloi and aloi2, of the same length ; Output: a list consisting of items that "match" in corresponding locations in the two input lists. (check-expect (all-matches (list 1 2 5) (list 1 3 5)) (list 1 5)) (check-expect (all-matches (list 1 2 5) (list 2 4 6)) empty) (check-expect (all-matches empty empty) empty) (check-expect (all-matches (list 4) (list 4)) (list 4))

Decision time: on which input(s) to recur? Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: ??? ??? Recursive result: Original result: (list 1 5)

Decision time Original inputs: (list 1 2 5) (list 1 3 5) ; Input: lists aloi and aloi2, of the same length Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: ??? ??? Three basic choices Shorten the first list; leave other unchanged Shorten the second list; leave first unchanged Shorten both lists More exotic choice Shorten first list, lengthen the second (!) Base case: first list is empty (but second could be huge!) For this problem: which one? Shorten both; otherwise recursive input doesn't meet input spec (equal-length lists)

Decision time Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: (list 2 5) (list 3 5) Recursive result: (list 5) Original result: (list 1 5)

Flesh out recursive diagram Original inputs: (list 1 2 5) (list 1 3 5) Recursive inputs: (list 2 5) (list 3 5) Recursive result: (list 5) Cons a 1 onto the recursive result? Cons (first aloi) onto recursive result? Original result: (list 1 5) Time to draw another example!

Flesh out recursive diagram Original inputs: (list 1 2 5) (list 2 3 5) Recursive inputs: (list 2 5) (list 3 5) Recursive result: (list 5) Cons a 1 onto the recursive result? NO! Cons (first aloi) onto recursive result? NO! Cons (first aloi) onto recursive result ONLY if the two "firsts" match? Yes! Original result: (list 5)

Write the call-structure and template (define (all-matches aloi aloi2) (cond [??? Wait…what are the possible kinds of input? Each of aloi and aloi2 could be empty or cons!

Write the call-structure and template (define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) …] [(and (empty? aloi) (cons? aloi2)) …] [(and (cons? aloi) (empty? aloi2)) …] [(and (cons? aloi) (cons? aloi2)) …])) For our particular procedure, where the lengths must be the same, two of these never occur

Write the call-structure and template (define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) …] [(and (cons? aloi) (cons? aloi2)) …])) What goes in the … places? For the first, the base case For the second, something involving first and rest of the two lists The "rests" are involved in a recursive call (because of our diagram)

Write the code! (define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) …] [(and (cons? aloi) (cons? aloi2)) ... (first aloi) … (first aloi2) … (all-matches (rest aloi) (rest aloi2))])) Cons (first aloi) onto recursive result ONLY if the two "firsts" match? Yes! Work with your neighbor to fill in the second case. (The first is empty)

Write the code! (define (all-matches aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) empty] [(and (cons? aloi) (cons? aloi2)) (if (= (first aloi) (first aloi2)) (cons (first aloi) (all-matches (rest aloi) (rest aloi2))) (all-matches (rest aloi) (rest aloi2)))]))

New Problem! Which list is longer? ; Input: two int lists aloi1 and aloi2 ; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) …) Test cases?

Which list is longer? ; Input: two int lists aloi and aloi2 ; Output: a boolean, true if aloi is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi aloi2) …) (check-expect (longer? (list 1 2 5) (list 1 3)) true) (check-expect (longer? (list 1 2) (list 2 4 6)) false) (check-expect (longer? empty empty) false) (check-expect (longer? (list 4) empty) true) (check-expect (longer? empty (list 4)) false)

Decision time Original inputs: (list 1 2 5) (list 1 3) Recursive inputs: ??? ??? Recursive result: ??? Original result: true  could shorten one list, the other, or both!

Decision time Original inputs: (list 1 2 5) (list 1 3) Recursive inputs: (list 2 5) (list 3) Recursive result: true Copy recursive result? Original result: true

Decision time Original inputs: (list 1 2) (list 2 4 6) Recursive inputs: (list 2) (list 4 6) Recursive result: false Copy recursive result? Original result: false

Another diagram! Original inputs: (list 4) , empty Recursive inputs: empty, NA Recursive result: This must be another base case! If first list empty: false If both empty: false If first cons, second empty: true Otherwise recur on both and copy recursive result Original result: true

Which list is longer? Template? ; Input: two int lists aloi1 and aloi2 ; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) …) (check-expect (longer? (list 1 2 5) (list 1 3)) true) (check-expect (longer? (list 1 2) (list 2 4 6)) false) (check-expect (longer? empty empty) false) (check-expect (longer? (list 4) empty) true) (check-expect (longer? empty (list 4)) false) Template?

Which list is longer? ; Input: two int lists aloi1 and aloi2 ; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) (cond [(and (empty? aloi1) (empty? aloi2)) …] [(and (cons? aloi1) (empty? aloi2)) … (first aloi1)… (rest aloi1) … ] [(and (empty? aloi1) (cons? aloi2)) … (first aloi2)… (rest aloi2) … ] [(and (cons? aloi1) (cons? aloi2)) … (first aloi1)… (rest aloi1) … (first aloi2)… (rest aloi2) … ] there's likely to be a recursive call in the last line, and possibly the two before it.

Fill in ; Input: two int lists aloi1 and aloi2 ; Output: a boolean, true if aloi1 is longer than aloi2, ; false if they're the same length or aloi2 is longer. (define (longer? aloi1 aloi2) (cond [(and (empty? aloi1) (empty? aloi2)) false] [(and (cons? aloi1) (empty? aloi2)) true] [(and (empty? aloi1) (cons? aloi2)) false] [(and (cons? aloi1) (cons? aloi2)) (longer? (rest aloi1) (rest aloi2))]))

A racket built-in (which you'll be writing for HW) (member item lst): true if item is in the list; false otherwise. Let's use this to write "intersect", which takes two lists and produces a list of things that are in both. ;; intersect: (int list) * (int list)-> (int list) ;; input: alod1, a list of ints ;; alod2, another list of ints ;; output: a list that’s identical to alod1, except that items not in alod2 ;; are deleted. In short, elements in both alod1 and alod2.

Recursive diagram Original inputs: (list 1 2 5) (list 1 3 2) Recursive inputs: (list 2 5) (list 1 3 2) Recursive result: (list 2) cons 1 (i.e., (first aloi)) onto the result because 1 is in (list 1 3 2); if it were not, we'd just return the recursive result Original result: (list 1 2)

Here member served as a helper procedure ;; intersect: (int list) * (int list)-> (int list) ;; input: alod1, a list of ints ;; alod2, another list of ints ;; output: a list that’s identical to alod1, except that items not in alod2 ;; are deleted. In short, elements in both alod1 and alod2. (define (intersect? aloi aloi2) (cond [(and (empty? aloi) (empty? aloi2)) empty] [(and (cons? aloi) (empty? aloi2)) empty] [(and (empty? aloi) (cons? aloi2)) empty] [(and (cons? aloi) (cons? aloi2)) (if (member (first aloi) aloi2) (cons (first aloi) (intersect (rest aloi) (rest aloi2))) (intersect (rest aloi) (rest aloi2)))])) Here member served as a helper procedure You'll often want to write your own helpers Mention that "member" here is like cons, in being a builtin…but since you could have written it (and will) it's a little different, too.

One more challenge: list reversal Define the problem by examples, for expedience: (check-expect (my-reverse (list 1 2 3)) (list 3 2 1)) (check-expect (my-reverse empty) empty) (check-expect (my-reverse (list 1)) (list 1))

;; my-reverse: (int list) -> (int list) ;; input: alod, a list of ints ;; ;; output: a list that’s contains the same items as alod, ;; but in reverse order (check-expect (my-reverse (list 1 2 3)) (list 3 2 1)) (check-expect (my-reverse empty) empty) (check-expect (my-reverse (list 1)) (list 1))

Recursive diagram Original input: (list 1 2 5) Recursive inputs: (list 2 5) Recursive result: (list 5 2) Stick (first aloi) on as the last item in the list? Could write a helper to do this… Original result: (list 5 2 1)

Bad idea This approach to reversing a list ends up being slow and complicated Turns out there's an easier way Involves generalizing the problem Oddly, in CS, sometimes it's easier to solve a more general problem than a more specific one! Finding the right "generalized problem" requires insight and experience, alas.

Reverse-with-tail > (reverse-with-tail (list 1 2 3) (list 4 5)) (list 3 2 1 4 5) > (reverse-with-tail (list 1 2 3) empty) (list 3 2 1) ;; reverse-with-tail: (int list) * (int list) -> (int list) ;; input: aloi, a list of integers ;; tail, another list of integers ;; output: the elements of aloi, in reverse order, followed by ;; those of tail, in their original order

Why is this a good idea? If we can write reverse-with-tail, then reverse becomes easy: (define (reverse aloi) (reverse-with-tail aloi empty))

Recursive diagram Original input: (list 1 2 5) (list 3 4) Recursive inputs: (list 2 5) ??? Recursive result: (list 5 2 1 3 4) just copy the recursive result! Original result: (list 1 5 2 3 4)

Big idea from aloi, tail, recur to (rest aloi), (cons (first aloi) tail) First list gets shorter, so we eventually hit a base case (first list empty) Second list grows!

code! (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(and (cons? aloi) (empty? tail)) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))] [(and (cons? aloi) (cons? tail)) (cons (first aloi) tail)))]))

Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(and (cons? aloi) (empty? tail)) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))] [(and (cons? aloi) (cons? tail)) (cons (first aloi) tail)))]))

Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) empty] [(and (empty? aloi) (cons? tail)) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

Simplify (define (reverse-with-tail aloi tail) (cond [(and (empty? aloi) (empty? tail)) tail] [(and (empty? aloi) (cons? tail)) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

Simplify (define (reverse-with-tail aloi tail) (cond [(empty? aloi) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))

Simplify (define (reverse-with-tail aloi tail) (cond [(empty? aloi) tail] [(cons? aloi) (reverse-with-tail (rest aloi) (cons (first aloi) tail)))]))