Presentation is loading. Please wait.

Presentation is loading. Please wait.

Conditionals and Recursion "To iterate is human, to recurse divine." - L. Peter Deutsch.

Similar presentations


Presentation on theme: "Conditionals and Recursion "To iterate is human, to recurse divine." - L. Peter Deutsch."— Presentation transcript:

1 Conditionals and Recursion "To iterate is human, to recurse divine." - L. Peter Deutsch

2 If, When, Unless We’ve already learned about LISP’s if construct (if test then-result else-result) The else-result is actually optional, with a default return value of NIL There are also macros for similar conditionals: (when test result) (unless test result) when returns its result if the test is true, NIL otherwise unless returns its result when the test is not true, NIL otherwise

3 Cond A more useful construct that allows for choosing between multiple conditions is cond (cond (test S-expression*)*) >(cond ((> 5 20) 'wrong) ((< 5 20) 'right) (t 'not-reached)) RIGHT Good programming style always includes a t condition at the end – Default return value is NIL

4 Recursion A function calls itself An extremely powerful and expressive technique Easier to do in LISP than in imperative languages (Java, C++), but still challenging at first Using LISP will give you new respect for and understanding of recursion

5 Example 1: Height of a Binary Tree (defun tree-height (x) (if (atom x) ;Test 0 ;Base Case (1+ (max (tree-height (car x)) ;Recursive Case (tree-height (cdr x)))) ))

6 Cases Any working recursive function must have at least two cases: – Base Case: Indicates when to stop Smallest possible problem instance (empty list, zero, etc.) – Recursive Case: Calls the function again, but on different arguments Formally, the arguments in recursive calls must be “smaller” in some way (shorter list, closer to zero, etc.) May have multiple base and/or recursive cases

7 Example 2: Average (defun count (x) ; Same as LISP’s length function (if (atom x) 0 (1+ (count (cdr x))) )) (defun sum (x) (if (atom x) 0 (+ (car x) (sum (cdr x))) )) (defun average (x) (/ (sum x) (count x)))

8 Tail Recursion Tail recursive functions do no work after the recursive call. The function returns whatever the recursive call returns Can be executed more efficiently by the LISP system Often accomplished by introducing an extra accumulator parameter

9 Example 3: Tail Recursive Average (defun count (x acc) (if (atom x) acc (count (cdr x) (1+ acc)) )) (defun sum (x acc) (if (atom x) acc (sum (cdr x) (+ (car x) acc)) )) (defun average (x) (/ (sum x 0) (count x 0)))

10 Example 4: Single Pass Average The last example still had to traverse the list twice: once for count and once for sum Why not give average accumulators? (defun average-help (x count sum) (if (atom x) (/ sum count) (average-help (cdr x) (1+ count) (+ (car x) sum)) )) (defun average (x) (average-help x 0 0))

11 Conclusion on Tail Recursion Often need to introduce accumulator(s) and helper functions to hide accumulators from users Not every recursive function can be rewritten using tail recursion – For example, tree-height has two recursive calls

12 Trace When debugging, it is often useful to trace calls of the recursive function (trace function-name) Causes every call of the recursive function to be printed along with its call depth Turn off using untrace (untrace function-name)

13 Trace Example >(trace average-help) (AVERAGE-HELP) >(average '(5 1 30 4)) 1> (AVERAGE-HELP (5 1 30 4) 0 0) 2> (AVERAGE-HELP (1 30 4) 1 5) 3> (AVERAGE-HELP (30 4) 2 6) 4> (AVERAGE-HELP (4) 3 36) 5> (AVERAGE-HELP NIL 4 40) <5 (AVERAGE-HELP 10) <4 (AVERAGE-HELP 10) <3 (AVERAGE-HELP 10) <2 (AVERAGE-HELP 10) <1 (AVERAGE-HELP 10) 10 >(untrace average-help) (AVERAGE-HELP)


Download ppt "Conditionals and Recursion "To iterate is human, to recurse divine." - L. Peter Deutsch."

Similar presentations


Ads by Google