Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. September 26th, 2010 Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (1/48) Lecture Outline Memory Management, Bindings, Scope contd Dynamic Scope Recursion, Iteration, and Last Call Optimization Recursion Iteration and Tail Recursion Exceptions Chapter 2 Summary Summary Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (2/48)
Dynamic Scope In dynamically scoped languages, free identifiers are looked-up in the caller s environment rather than in the environment corresponding to lexical (textual) regions of code. Example (Dynamic scope in Emacs Lisp) (let ((x 1)) (defun showx () (message "x = %d" x)) (let ((x 2)) (showx))) The no-argument procedure showx has one free variable in its body, 1 which is given the value 1 in the lexically enclosing environment. When showx is called, it needs to lookup x, but it does that using the caller s environment, which now includes a binding of x to 2 thus, 2 is displayed. Try it! Open the program code/scope.el in emacs and execute it (C-x X-e). 1 Well, it has two: message is free as well. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (3/48) Dynamic Scope contd In some languages, we can achieve the effects of dynamic scoping with special constructs. Example (Lexical and dynamic scoping in Scheme) lexical scoping: dynamic scoping: (let ((x 1)) (define (showx) (display x)) (let ((x 2)) (showx)) ;; 1 (showx)) ;; 1 (let ((x 1)) (define (showx) (display x)) (fluid-let ((x 2)) (showx)) ;; 2 (showx)) ;; 1 let creates a new environment and introduces new bindings; 2 when showx (left) is called, x is looked up in the environment at its definition, where x equals 1. fluid-let does not create any environment, but rather temporarily modifies bindings in the enclosing environment; when showx is called (right), x is looked up as previously, but now it equals 2. 2 let in Scheme roughly corresponds to local in Oz. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (4/48)
Dynamic Scope contd In different languages similar constructs may have different effects, or have similar effects despite different mechanisms. Example (Dynamic scoping) Bash: x=hello showx() { echo $x; } test() { local x=dolly; showx; } test # dolly Perl: $x = "hello"; sub showx { print $x; } sub test { local $x = "dolly"; &showx; } &test # dolly &showx # hello In Bash, local introduces a local variable, but functions do not capture definition environments, and showx uses the binding for x available where it is called. In Perl, local temporarily modifies bindings in the enclosing environment, and showx within test looks-up the global x when it has the temporary value dolly. Try it! Execute the code in code/scope.sh and code/scope.pl. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (5/48) Lecture Outline Memory Management, Bindings, Scope contd Dynamic Scope Recursion, Iteration, and Last Call Optimization Recursion Iteration and Tail Recursion Exceptions Chapter 2 Summary Summary Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (6/48)
Recursion What is recursion? Recursion: see recursion. Recursion is a fundamental concept in mathematics, and in computer science in particular, in functional programming. A recursive procedure is one that calls itself within its own body. 3 A recursive computation is one in which a recursive procedure is called repetitively so that the result of each call deps on the result of the subsequent calls. In a recursive computation, the stack of activation records (the semantic stack in the abstract machine in Oz) grows with each nested call, and shrinks when nested calls are exited. 3 There are other variants of recursion, e.g., mutual recursion; see below. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (7/48) Recursion contd Recursive computations need appropriate stopping conditions otherwise, stack overflow is inevitable. Example (Recursive procedure) declare fun {Factorial N} if N < 2 then 1 else N * {Factorial N - 1} Factorial computes the factorial of its argument: given a non-negative integer n, it computes n! = n (n 1)... 1. 4 Factorial is recursive there is a call to Factorial within Factorial s body. 4 Incidentally, this implementation computes incorrectly with negative integers as well. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (8/48)
Recursion contd If the nested call in a recursive procedure is not the last statement to be executed within the body, the procedure specifies a recursive computation. Let us see how the computation of {Factorial 3} proceeds we need to translate Factorial (and its application) into the kernel language. Example (Recursive procedure, quasi-kernel language) local Factorial N Result in Factorial = proc {$ N?Result} if N < 2 then Result = 1 else local NMinusOne NestedResult in NMinusOne = N - 1 {Factorial NMinusOne NestedResult} Result = N * NestedResult N = 3 {Factorial N Result} We shall visualize the steps using a slightly modified notation. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (9/48) Recursion contd Example (Application of a recursive procedure) 1. [ (local F N R in..., {}) ] { }... (nested declarations, sequence splitting) 5. [ (F = proc..., {F:v1, N:v2, R:v3}),... ] { v1, v2, v3 }... (binding F, sequence splitting) 8. [ ({F N R}, {F:v1, N:v2, R:v3}) ] { v1=(proc {$ N R}..., {F:v1}), v2=3, v3 } 9. [ (if N < 2..., {F:v1, N:v2, R:v3}) ] { v1=(proc {$ N R}..., {F:v1}), v2=3, v3 }... (evaluating the condition, nested declarations, sequence splitting) 15. [ ({F NM NR}, {F:v1, N:v2, R:v3, NM:v4, NR:v5}), (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5 } 16. [ (if N < 2..., {F:v1, N:v4, R:v5}), (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5 }... (evaluating the condition, nested declarations, sequence splitting) Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (10/48)
Recursion contd Example (Application of a recursive procedure contd) 22. [ ({F NM NR}, {F:v1, N:v4, R:v5, NM:v6, NR:v7}), (R = N * NR, {F:v1, N:v4, R:v5, NM:v6, NR:v7}), (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5, v6=1, v7 } 23. [ (if N < 2..., {F:v1, N:v6, R:v7}), (R = N * NR, {F:v1, N:v4, R:v5, NR:v7}), (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5, v6=1, v7 } 24. [ (R = 1, {F:v1, N:v6, R:v7}), (R = N * NR, {F:v1, N:v4, R:v5, NR:v7}), (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5, v6=1, v7 } 25. [ (R = N * NR, {F:v1, N:v4, R:v5, NR:v7}), (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5, v6=1, v7=1 } 26. [ (R = N * NR, {F:v1, N:v2, R:v3, NM:v4, NR:v5}) ] { v1=(...), v2=3, v3, v4=2, v5=2, v6=1, v7=1 } 27. [ ] { v1=(...), v2=3, v3=6, v4=2, v5=2, v6=1, v7=1 } Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (11/48) Iteration and Tail Recursion Examine the content of the semantic stack during an execution of the Factorial program: it grows linearly with each recursive application of Factorial (steps 8, 15, 22); it shrinks linearly when the stop condition (N < 2) is met and the postponed computations are resumed and completed (steps 24 27). The computation is recursive. But we can do better with an alternative design: 5 Instead of accumulating postponed operations on the stack, start the computation from the other. During the computation, the stack will be kept constant in size. This approach is commonly called iteration. 5 We could also do better with explicit state, but our current model does not support that. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (12/48)
Iteration and Tail Recursion contd We need to rewrite Factorial so that the recursive calls receive an additional argument, which keeps the partial result computed so far. Example (Iteration) declare fun {Factorial N} fun {Iterate Iterator Accumulator} if Iterator > N then Accumulator else {Iterate Iterator+1 Accumulator*Iterator} in {Iterate 2 1} When no more recursion is needed (Iterator > n), the result has been completely calculated, and can be returned without going back through a chain of postponed computations. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (13/48) Iteration and Tail Recursion contd To see how the computation proceeds on the abstract machine, we need a kernel version of the new Factorial. Example (Iteration, quasi-kernel language) local Factorial N Result in Factorial = proc {$ N?Result} local Iterate Iterator Accumulator in Iterate = proc {$ Iterator Accumulator} if Iterator > N then Result = Accumulator else local NextIterator UpdatedAccumulator in NextIterator = Iterator + 1 UpdatedAccumulator = Accumulator * Iterator {Iterate NextIterator UpdatedAccumulator} Iterator = 2 Accumulator = 1 {Iterate Iterator Accumulator} N = 3 {Factorial N Result} Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (14/48)
Iteration and Tail Recursion contd We will not go through the computation manually here, but you are free to try it out. Instead, we can summarize both computations as follows: Example (Recursive vs. iterative computation) recursive: iterative: {Factorial 4} 4 * {Factorial 3} 4 * (3 * {Factorial 2}) 4 * (3 * (2 * {Factorial 1})) 4 * (3 * (2 * 1)) 4 * (3 * 2) 4 * 6 24 {Factorial 4} {Iterate 2 1} {Iterate 3 2} {Iterate 4 6} {Iterate 5 24} 24 The recursive version accumulates postponed operations, the iterative version does not. In the recursive version, the stack grows linearly with input, in the iterative it is kept constant. 6 6 There are variations in stack size throughout both computations, but at each recursive call in the iterative version the stack has the same size. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (15/48) Iteration and Tail Recursion contd In both versions, each recursive call causes new variables to be allocated in the single assignment store. However, in the recursive version, all these local variables are reachable and thus persistent until the procedure reaches its stop condition, and the computation begins to fold back through the postponed operations; in the iterative version, once a recursive call is made some of the local variables are no longer reachable, and may thus be deallocated. Stack and store in recursive and iterative computations Given an input of size n, the stack and store sizes are: Recursive computation Iterative computation Stack size O(n) O(1) Store size O(n) O(1) Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (16/48)
Iteration and Tail Recursion contd Recursive procedures that specify iterative processes are usually called tail-recursive, since the recursive call is the last one to be executed within the body. The technique that allows a tail-recursive procedure to return immediately instead of going back through a sequence of stacked call frames 7 is called last call optimization. In some languages (e.g., Oz), last call optimization is automatically applied to tail-recursive procedures. In some languages (e.g., C), last call optimization is applied or not, deping on how the program is compiled. In some languages (e.g., Java), there is no last call optimization. 7 Semantic statements in Oz. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (17/48) Iteration and Tail Recursion contd Try it! Compile and execute the two Oz programs code/recursive.oz and code/iterative.oz: $ ozc -x recursive.oz &&./recursive $ ozc -x iterative.oz &&./iterative Compare their behaviour and examine the source code. Try to run the programs in the Oz debugger: $ ozd recursive $ ozd iterative Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (18/48)
Iteration and Tail Recursion contd Try it! Compile and execute the C program code/tail.c, once without and once with last call optimization: $ gcc -g -O0 tail.c -o tail &&./tail $ gcc -g -O2 tail.c -o tail &&./tail Compare the behaviour and examine the source code. Run the code in a debugger and examine the stack: 8 $ gdb tail 8 Type start to start the program, s to step it, bt to examine the stack. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (19/48) Iteration and Tail Recursion contd Try it! Compile and execute the Java program code/tail.java: $ javac tail.java && java tail Observe its behaviour and examine the source code. Run the program in a Java debugger: 9 $ jdb tail 9 Type stop in tail.tail to set a breakpoint, run to start the program, step to step it, where to examine the stack. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (20/48)
Lecture Outline Memory Management, Bindings, Scope contd Dynamic Scope Recursion, Iteration, and Last Call Optimization Recursion Iteration and Tail Recursion Exceptions Chapter 2 Summary Summary Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (21/48) Exceptions If we a re lucky, our programs run as they should, receiving the expected input and producing the expected output. What if something goes wrong? Example (Summing up nodes in a tree) fun {Sum Tree} case Tree of leaf(n) then N [] tree(n Left Right) then N + {Sum Left} + {Sum Right} What if Tree is neither a leaf nor a tree record? What if N is not a number? Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (22/48)
Exceptions contd We can check for unusual situations and report them with special values. Example (Summing up nodes in a tree contd) fun {Sum Tree} case Tree of leaf(n) then if {Number.is N} then N else nan(n) 10 [] tree(n Left Right) then L = {Sum Left} R = {Sum Right} in if {Not {Number.is N}} then nan(n) elseif {Not {Number.is L}} then L elseif {Not {Number.is R}} then R else N + L + R else nat(tree) 11 Sum becomes somewhat complicated: we need to test each used value within Sum, and we also need to test the returned value outside of Sum. If we don t, the computation may crash inside or outside of Sum. 10 nan stands for not a number. 11 nat stands for not a tree. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (23/48) Exceptions contd The problem is further complicated when recursive procedures are used. Example (Summing up nodes in a tree contd) Tree = tree(0 tree(1 tree(2 leaf(4) leaf(5)) tree(6 leaf(7) leaf))) {Browse {Sum Tree}} There is a problem: one of the elements of the examined tree has incorrect structure. The nested call which gets leaf as input returns nat(leaf). This value is tested and returned multiple times until the initiall call to Sum finally returns. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (24/48)
Exceptions contd What we really want is a way to return the special value immediately, without reinvoking the postponed computations. Example (Summing up nodes in a tree contd) fun {Sum Tree} case Tree of leaf(n) then if {Number.is N} then N else return nan(n) immediately [] tree(n Left Right) then... else return nat(tree) immediately For this to work, we need to have a means for discarding semantic statements (call frames) from the semantic stack (the call stack). Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (25/48) Exceptions contd An early attempt at such non-local exits (backward jumps over multiple frames on the stack) uses continuations. Example (Apping lists in Scheme) (define (multi-app. lists) (call-with-current-continuation (lambda (continuation) (let multi-app ((lists lists)) (cond ((null? lists) ()) ((list? (car lists)) (app (car lists) (multi-app (cdr lists)))) (else (continuation (cons not-a-list (car lists))))))))) (multi-app (1 2 3) (4 5) (6)) ;; => (1 2 3 4 5 6) (multi-app (1 2 3) ops! (6)) ;; => (not-a-list. ops) multi-app can be applied to any number of lists, and returns a concatenation of all the lists. If any of the arguments is not a list, multi-app calls the continuation and exits imemdiately with an error message. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (26/48)
Exceptions contd Another low-level approach to handling exceptional situations is to save the state of the execution environment (e.g., the stack and the static memory), and perform an explicit jump to that state (reconstruct the memory content) if something goes wrong. Example (Integer division in C) int divide(int a, int b) { if (0 == b) longjmp(target, 1); // jump if /0 else return a/b; } int main() { if (!setjmp(target)) // jump to here printf("%i/%i = %i\n", 1, 2, divide(1,2)); // fine printf("%i/%i = %i\n", 1, 0, divide(1,0)); // ops, jump! printf("%i/%i = %i\n", 2, 1, divide(2,1)); // never reached else { puts ("cannot divide by zero"); // jump action }... // proceed Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (27/48) Exceptions contd Most modern programming languages provide a convenient abstraction for handling pathological situations exceptions. Special syntactic constructs are used to set handlers for arriving exceptions (e.g., catch, rescue, except); generate exceptions (e.g., throw, raise); perform cleanup actions (e.g., finally, ensure). Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (28/48)
Exceptions contd Example (Exceptions) fun {Length List} case List of nil then 0 [] _ Tail then {Length Tail} + 1 else raise nal(list) List = a b c try {Browse {Length List}} catch nal(message) then {Browse "Length -- cannot process a non-list object: "#Message} Length recursively calculates the lenght of a list. If the input is not a list, an exception is thrown. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (29/48) Exceptions contd To implement exceptions, we need to ext the kernel language, both syntactically and sematically. The syntax of exception statements statement ::=... try statement catch id then statement raise id Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (30/48)
Exceptions contd Semantics of the try statement The semantic statement is: The execution rule is: (try statement 1 catch id then statement 2, E) 1. Push onto the stack the semantic statement (catch id then statement 2, E) 2. Push onto the stack the semantic statement ( statement 1, E) Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (31/48) Exceptions contd Semantics of the raise statement The semantic statement is: The execution rule is: (raise id, E) 1. If the semantic stack is empty, stop stop and report an uncaught exception. 2. Else pop the first semantic statement from the stack. If it is not a catch statement, go to step 1. 3. The popped statement is (catch id c then statement c, E c ) Push onto the stack the semantic statement ( statement c, E c + { id c E( id ) Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (32/48)
Exceptions contd Semantics of the catch statement The semantic statement is: The execution rule is: (catch id then statement, E) Do not do anything. (The catch statement is equivalent to the skip statement.) Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (33/48) Exceptions contd Example (Exceptions, quasi-kernel language) local Exception Message in try Exception = exception(message) Message = message raise Exception catch Exception then case Exception of exception() then {Browse Message} else raise Exception The catch clause pattern-matches the exception raised in the try clause; if it did not match, it would be re-raised. Try to execute the program manually, or use the Oz debugger. 12 12 The Oz debugger does not simulate the abstract machine exactly as specified in CTMCP. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (34/48)
Exceptions contd Note: Code enclosed within a try block is not executed as a transaction: as with complex (nested) unification, any bindings made until an exception is raised remain in effect at the time and after the exception is handled. Example (Non-transactional behaviour of try blocks) local A B C in try A = 1 B = 2 raise B C = 3 catch E then {Browse E} {Browse A#B#C} What will be displayed? Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (35/48) Exceptions contd Example (Non-transactional behaviour of try blocks contd) 1. [ (local A in..., {}) ] { } 2. [ (local B in..., {A:v1}) ] { v1 } 3. [ (local C in..., {A:v1, B:v2}) ] { v1, v2 } 4. [ (try... {Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1, v2, v3 } 5. [ (try..., {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1, v2, v3 } 6. [ (A=1 B=2 raise B C=3, {A:v1, B:v2, C:v3}), (catch E..., {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1, v2, v3 } Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (36/48)
Exceptions contd Example (Non-transactional behaviour of try blocks contd) 7. [ (A=1, {A:v1, B:v2, C:v3}), (B=2 raise B C=3, {A:v1, B:v2, C:v3}), (catch E..., {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1, v2, v3 } 8. [ (B=2 raise B C=3, {A:v1, B:v2, C:v3}), (catch E..., {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1=1, v2, v3 } 9. [ (B=2, {A:v1, B:v2, C:v3}), (raise B C=3, {A:v1, B:v2, C:v3}), (catch E..., {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1=1, v2, v3 } 10. [ (raise B C=3, {A:v1, B:v2, C:v3}), (catch E..., {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1=1, v2=2, v3 } Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (37/48) Exceptions contd Example (Non-transactional behaviour of try blocks contd) 11. [ (raise B, {A:v1, B:v2, C:v3}), (C=3, {A:v1, B:v2, C:v3}), (catch E {Browse E}, {A:v1, B:v2, C:v3}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1=1, v2=2, v3 } 12. [ ({Browse E}, {A:v1, B:v2, C:v3, E:v2}), ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1=1, v2=2, v3 } 13. 2 displayed in the browser window [ ({Browse A#B#C}, {A:v1, B:v2, C:v3}) ] { v1=1, v2=2, v3 } 14. 1#2#_ displayed in the browser window [ ] { v1=1, v2=2, v3 } Note: The variables v 1 and v 2 remained bound to their values after the raise and catch statements had been executed; v 3 remained unbound. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (38/48)
Exceptions contd In the practical language, we can use a syntactic extensions that allow us to use raise with value expressions, not just identifiers; pattern-match exceptions directly in the catch clause; use multiple catch clauses with different patterns. Example (Pattern-matching catch, multiple handlers) try... catch exception(message) then... [] error#[message Cause] then...... [] AnyOtherException then... raise whatever#you#wish Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (39/48) Exceptions contd Multiple catch clauses with arbitrary patterns are equivalent to a sequence of nested catch and case statements, with a final raise statement if needed. Example try... catch exception(message) then... [] error#[message Cause] then... above: practical language right: kernel language try... catch Ex then case Ex of exception(1:message) then... else case Ex of # (1:Type 2:Desc) then case Type of error() then case Desc of (1:Message 2:Rest) then case Rest of (1:Cause 2:nil) then... else raise Ex else raise Ex else raise Ex else raise Ex Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (40/48)
Exceptions contd So what are exceptions? Example (Exceptions in Ada) code/exception.adb with text_io; procedure main is funnybunny : exception; begin begin raise funnybunny; exception when funnybunny => Text_IO.Put_Line("funnybunny caught!"); ; main; In some languages (e.g., Ada), exceptions are values of the built-in type exception. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (41/48) Exceptions contd Example (Exceptions in C++) code/exception.cpp #include <iostream> class FunnyBunny { }; int main() { try { throw FunnyBunny(); } catch (FunnyBunny fb) { std::cout << "funnubunny caught!" << std::l; } return 0; } In some languages (e.g., C++), objects of any class can be thrown as exceptions. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (42/48)
Exceptions contd Example (Exceptions in Java) code/exception.java public class exception { } public static void main(string[] args) { try { throw new Throwable() {}; } catch (Throwable t) { System.out.println("funnybunny caught!"); } } In some languages (e.g., Java), exceptions are objects of a class derived from some specific class in the built-in hierarchy (e.g., exting Exception or implementing Throwable). Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (43/48) Exceptions contd Example (Procedures as exceptions in Oz) try raise proc {$ Message} {Browse Message} catch Exception then {Exception funnybunny} In some languages (e.g., Oz), any value can be raised as an exception. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (44/48)
Exceptions contd Example (Exceptions in Perl) code/exception.pl #!/usr/bin/perl sub divide { my ($a, $b) = @_; my $result; eval { $result = $a/$b; }; die "cannot divide by zero!" if $@; return $result; } print ÷(1,0); In some languages (e.g., Perl), we can execute code within a nested evaluation loop, and test for error conditions to act appropriately. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (45/48) Lecture Outline Memory Management, Bindings, Scope contd Dynamic Scope Recursion, Iteration, and Last Call Optimization Recursion Iteration and Tail Recursion Exceptions Chapter 2 Summary Summary Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (46/48)
Chapter 2 Summary 2.1 Defining practical programming language: syntax (EBNF grammars), semantics. 2.2 The single assignment store: defining the abstract machine. 2.3 Kernel language: defining the syntax of the declarative sequential kernel language. 2.4 Kernel language semantics: rules for execution of semantic statements. 2.5 Memory management: tail recursion, garbage collection. 2.6 From kernel language to practical language: syntactic sugar, linguistic abstraction. 2.7 Exceptions: extension of the kernel language. 2.8 Advanced topics: functional languages, unification, typing.... and lecture handouts. Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (47/48) Lecture Outline Memory Management, Bindings, Scope contd Dynamic Scope Recursion, Iteration, and Last Call Optimization Recursion Iteration and Tail Recursion Exceptions Chapter 2 Summary Summary Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming. (48/48)