Lecture 8: Recursion and Iteration. Exceptions. Declarative Programming.

Similar documents
Lecture 5: Declarative Programming. The Declarative Kernel Language Machine. September 12th, 2011

Lecture 6: The Declarative Kernel Language Machine. September 13th, 2011

Functional Programming. Pure Functional Programming

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

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

Lecture 4: The Declarative Sequential Kernel Language. September 5th 2011

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

Programming Language Concepts, cs2104 Lecture 04 ( )

CS 360 Programming Languages Interpreters

Notes on Higher Order Programming in Scheme. by Alexander Stepanov

Run-time Environments - 2

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

Lecture 7: Type Systems and Symbol Tables. CS 540 George Mason University

Don t write anything in the field marked Eventuell ekstra ID. For each subtask, choose the answer you think is the most correct one.

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

Chapter 1. Fundamentals of Higher Order Programming

Control in Sequential Languages

G Programming Languages - Fall 2012

Le L c e t c ur u e e 5 To T p o i p c i s c t o o b e b e co c v o e v r e ed e Exception Handling

G Programming Languages - Fall 2012

Object Oriented Programming Exception Handling

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

Programming Languages Third Edition. Chapter 9 Control I Expressions and Statements

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

Lecture 21: Relational Programming II. November 15th, 2011

Introduction to Scheme

Functional Programming Languages (FPL)

Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003

Functional Programming. Pure Functional Languages

Run-time Environments

Run-time Environments

The role of semantic analysis in a compiler

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

Declarative Computation Model

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler so far

Functional Programming. Pure Functional Languages

Pace University. Fundamental Concepts of CS121 1

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

To figure this out we need a more precise understanding of how ML works

NOTE: Answer ANY FOUR of the following 6 sections:

Program Correctness and Efficiency. Chapter 2

Object-oriented programming. and data-structures CS/ENGRD 2110 SUMMER 2018

CS 314 Principles of Programming Languages

Programming Languages Third Edition. Chapter 10 Control II Procedures and Environments

A Third Look At Java. Chapter Seventeen Modern Programming Languages, 2nd ed. 1

COP4020 Programming Assignment 1 - Spring 2011

Lambda Calculus. Gunnar Gotshalks LC-1

Exceptions and Design

MIDTERM EXAMINATION - CS130 - Spring 2005

INF4820: Algorithms for Artificial Intelligence and Natural Language Processing. Common Lisp Fundamentals

CSCC24 Functional Programming Scheme Part 2

Lecture08: Scope and Lexical Address

CSCI-GA Scripting Languages

Programming Languages Third Edition. Chapter 7 Basic Semantics

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 11

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

Scheme Tutorial. Introduction. The Structure of Scheme Programs. Syntax

Modern Programming Languages. Lecture LISP Programming Language An Introduction

UNIT 3

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Run-time Environments. Lecture 13. Prof. Alex Aiken Original Slides (Modified by Prof. Vijay Ganesh) Lecture 13

Object Oriented Programming

CS558 Programming Languages

Functional Programming. Big Picture. Design of Programming Languages

Organization of Programming Languages CS3200/5200N. Lecture 11

Pierce Ch. 3, 8, 11, 15. Type Systems

CSC System Development with Java. Exception Handling. Department of Statistics and Computer Science. Budditha Hettige

Semantic Analysis. Compiler Architecture

G Programming Languages - Fall 2012

Design Issues. Subroutines and Control Abstraction. Subroutines and Control Abstraction. CSC 4101: Programming Languages 1. Textbook, Chapter 8

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

SCHEME AND CALCULATOR 5b

Putting the fun in functional programming

LECTURE 3. Compiler Phases

G Programming Languages - Fall 2012

Exception Handling. Sometimes when the computer tries to execute a statement something goes wrong:

CS 3 Introduction to Software Engineering. 3: Exceptions

A LISP Interpreter in ML

Recursion & Iteration

ECE 2400 Computer Systems Programming Fall 2018 Topic 1: Introduction to C

LECTURE 18. Control Flow

Exception Handling. Run-time Errors. Methods Failure. Sometimes when the computer tries to execute a statement something goes wrong:

CS558 Programming Languages

LECTURE 16. Functional Programming

Lambda Calculus see notes on Lambda Calculus

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

Syntax Errors; Static Semantics

Anatomy of a Compiler. Overview of Semantic Analysis. The Compiler So Far. Why a Separate Semantic Analysis?

CS 314 Principles of Programming Languages

Functions and Recursion. Dr. Philip Cannata 1

Lambda Calculus LC-1

CS 415 Midterm Exam Fall 2003

Lecture Outline. COOL operational semantics. Operational Semantics of Cool. Motivation. Lecture 13. Notation. The rules. Evaluation Rules So Far

Compiler Theory. (Semantic Analysis and Run-Time Environments)

Chapter 7 Control I Expressions and Statements

More Examples. Lecture 24: More Scala. Higher-Order Functions. Control Structures

About this exam review

PL Revision overview

Concepts Introduced in Chapter 7

Transcription:

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 &divide(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)