1 Recursion Jeff Parker, Merrimack College CS2 @ Dennison, June 2008 In order to understand recursion you just need to understand recursion. 2 Outline Recursion is important We use it to describe things (BNF) Many algorithms are best expressed recursively Our choice is not if we should teach it, but how to teach it Recursion is hard Our students don't understand it Our students fear it This talk hopes to provide Review of the literature More ideas than you can possibly use, and A framework to work within 3 How to teach it There are two theories on how to teach it: Students should Have a strong model of how it works, or Have a template for how to use it, without worrying so much about how it works [Long, Weide, Bucci] These are not as contradictory as they seem Understanding how it works well enough to predict what a new example does is important Understanding how it works does not help us solve new problems We need both skills. But we need more… 4 Framework for teaching Motivation As with any new notion, the student must have a reason to master the new idea. Need a problem they cannot solve without recursion Mental model of recursion Must be strong enough to allow student to test alternatives. Understanding of how to apply recursion The mental model helps us simulate action of function. Does not help us write the function in the first place. 5 Motivation We want examples that grab the students We don't have to explain in full detail - that comes later Look for examples in the following areas Images Language Text: pyramids, reverse – ASCII "graphics" Games and Puzzles Avoid fib() and factorial() Prefer power(base, exp) As well as problems that recursion can help us solve, we explore the richness of recursion 6 Images Images are excellent at capturing the idea Some of the images are recursive by nature Some are easy to describe recursively Introducing APIs needed to write examples is barrier If we are using these as motivation this isn't an issue Some images are distracting As much as we like them, they confuse our students 7 Dan Gries' Fractal Maker A system that lets students play with different fractal images Can select the depth of recursive calls Has a nice library of examples http://www.dangries.com/Flash/FractalMaker.html 8 Dolls 9 Images 10 Recursion in Language Noam Chomsky believes that the ability to recursively extend a sentence is hardwired. This is the man all tattered and torn, That kissed the maiden all forlorn, That milked the cow with the crumpled horn, That tossed the dog, That worried the cat, That killed the rat, That ate the malt That lay in the house that Jack built. Khad Gadya One little goat that Father bought for two zuzim. Daniel Everett has proposed the Pirahã language as a counter-example. 11 Recursion in Language An interesting exercise in inductive reasoning is to discuss the statement A King is a son of a King Is this true? Why or why not? George I ascended after James II was deposed. Does this prove that Prince Charles can never take the throne? If we assume it is true, what else can we say about Kings? 12 Other Motivating Examples 13 Student Mental Models [Kahney] analyzed student mental models Looping model – Recursion as a form of iteration Step Model – just follow the program one step at a time Return Value Model – Assumes each call returns at once Models in which Return returns to the main… Magic Model – No Clue Copies Model – Distinct invocations of a routine (the only correct model) Each Slugo is different Since then, other models have been suggested. Part of our task is to render other models untenable 14 Copies Model [George] argues that to teach Copies model, we must Show active flow of control (from caller to callee) Show passive flow of control (callee returns to caller) Understand the base case We can explain all this with linear recursion (single call) Pure Tail Recursion does not have observable passive flow Embedded Recursion may You can observe a lot just by watching - Yogi Berra Print a String void print(string str) { if (str.length() > 0) { char ch = str.at(0); string tail = str.substr(1, str.length()); print(tail); cout << ch; } } [Ford] Call on students to act out roles Each student has a different copy of this page I think it is important to make tail explicit, rather than a function call if (str.length() > 0) { ... print(str.substr(1, str.length())); 15 str ch tail print("STOP"); 16 Reverse a String To focus on passive flow, assemble work In this function, we build a string string reverse(string str) { if (str.length() == 0) return str; else { char ch = str.at(0); string tail = str.substr(1, str.length()); return tail + ch; } } str ch tail reverse("STOP"); 17 Teaching Models [Wu, Dale, and Bethel] identify 5 teaching models Three are concrete, two abstract Russian Dolls - smaller versions of the original (recursive call) and a doll that you cannot open (base case) Process Tracing – Use call tree [Kruse] or activation trace [Haynes] Stack Simulation – Show the underlying computer architecture used Mathematical Induction – Mathematical examples and Proof by Induction Structure template – Sample solutions and a template that they can fill in They believe that different students will prefer different approaches 18 Writing Recursive Routines The third leg of the stool is to write recursive routines When we present a recursive definition of the Factorial function, we have skipped the step that students find most difficult When we teach functions, we teach students to understand what the client needs, and to write a provider to implement it. Recursive routines are both client and provider [Long, Weide, Bucci]: Apply this to your problem of choice 19 Recursion in Text CS1 Students were given problem to reverse the elements of DNS name They had struggled to write an iterative solution w w w e d u . . d e n d e n i s i s o o n n . . e d u w w w 20 Reverse a string w/ three words string reverse3word(string str) { string::size_type pos = str.find(‘.’); string word = str.substr(pos+1, str.length(); return reverse2word(word) + “.” + str.substr(0, pos); } Of course, this does not work if there are no dots. Bullet-proof this with a check that pos is not negative w w w . d e n i s o n . e d u 21 Reverse a string string reverse3word(string str) { string::size_type pos = str.find(‘.’); if (string::npos == pos) return str; else { string word = str.substr(pos+1, str.length(); return reverse2word(word) + “.” + str.substr(0, pos); } } string reverse2word(string str) { string::size_type pos = str.find(‘.’); if (string::npos == pos) return str; else { string word = str.substr(pos+1, str.length(); return reverse1word(word) + “.” + str.substr(0, pos); } } string reverse1word(string str) { return str; } 22 Visualizing the Call Stack We have two copies of Pow3 on the stack This one has a value of n = 6 The arrow in bottom panel shows where the program is running The debugger shows the stack, for those that understand it 23 EROSI While the debugger has all the information, we do not see the two calls to power as distinct objects [George] proposed the EROSI (Explicit Representer of Subprogram Invocations) system that shows each invocation as a distinct object int main() { p = power(2, 13) power(2, 13) { … temp = power(2, 13/2); … return temp; power(2, 6) { … temp = power(2, 6/2); … return temp; Tracing Calls: Filling Consider the task of filling a region 25 Call Tracking Call trees are the gold standard [Kruse] Creating them requires solid understanding // Fill Boolean array image at point (row, col) void fill(bool image[MAX][MAX], int row, int col) { // Is the fill point within the graph? if ((row < 0) || (row >= MAX) || (col < 0) || (col >= MAX)) return; // Is the graph empty at the fill point? if (image[row][col]) return; // Turn on the point image[row][col] = true; // Try to fill in the surrounding area fill(image, row-1, col, level + 1); fill(image, row+1, col, level + 1); fill(image, row, col-1, level + 1); fill(image, row, col+1, level + 1); } 26 Mechanical Call Tracking Simplest mechanical aid is to print info as we enter function Adding indenting to show stack depth [Haynes] void fill(bool image[MAX][MAX], int row, int col, int level) { cout << indent(level) << "fill(" << row << ", " << col << ")\n"; ... // Fill in the surrounding area fill(image, row-1, col, level + 1); fill(image, row+1, col, level + 1); fill(image, row, col-1, level + 1); fill(image, row, col+1, level + 1); } fill(4, 4) fill(3, 4) fill(2, 4) fill(1, 4) fill(3, 4) fill(2, 3) fill(2, 5) fill(1, 5) fill(3, 5) 27 Mechanical Call Tracking Here we track which call (first, second, third…) filled each cell void fill(bool image[MAX][MAX], int row, int col, int & cnt, int count[MAX][MAX]) { // Is the fill point within the graph? if ((row < 0) || (row >= MAX) || (col < 0) || (col >= MAX)) return; // Is the graph empty at the fill point? if (image[row][col]) return; // Turn on the point image[row][col] = true; count[row][col] = ++cnt; // Try to fill in the surrounding area fill(image, row-1, col, cnt, count); fill(image, row+1, col, cnt, count); fill(image, row, col-1, cnt, count); fill(image, row, col+1, cnt, count); } 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 X X X 0 X X 3 4 X X 15 2 5 X 26 16 1 X X 25 17 23 X 0 X 18 22 X X 20 19 21 24 0 X X X X 0 0 0 0 0 0 X X 6 7 8 9 X X 0 0 0 X 13 12 11 10 14 X 0 0 0 0 X X X X X X 0 0 0 0 0 0 0 0 0 0 0 28 Dramatizations Ben-Ari suggests that we dramatize recursion He gives 3 examples. Each emphasizes the passive flow. Open a present (Improvement on nested Matryoshka Dolls) The receiver thanks the presenter to show passive flow Build a chain of N links by adding a link on passive path Count the nuts in a Chocolate Bar: assemble count 29 Summary Motivation Give students a reason to master a new idea. Mental model of the process Provide a mental model that they can use Reinforce with call tracing, call trees, etc. Understanding of how to apply recursion Use functional decomposition to break problem down Templates may help: should not be straight-jacket 30 Selected Sources [Ford] A framework for teaching Recursion, SIGCSE Bulletin, 1982. [Kahney] Modelling novice programmer behaviour. In: New horizons in educational computing,1984. [Haynes] Explaining Recursion to the Unsophisticated, SIGCSE Bulletin, September 1995 [Ben-Ari] Recursion: From Drama to Program, Journal of Computer Science Education, 11(3), 1997 [Wu, Dale, Bethel] Conceptual Models and Cognitive Learning Styles. SIGCSE 98 [Long, Weide, Bucci] ClientView First: An Exodus From ImplementationBiased Teaching, SIGCSE 1999 [George] EROSI – Visualizing Recursion and Discovering New Errors, SIGCSE 2000