Functional Programming Lists Pattern Matching Recursive Programming CTM

  • Slides: 36
Download presentation
Functional Programming: Lists, Pattern Matching, Recursive Programming (CTM Sections 1. 1 -1. 7, 3.

Functional Programming: Lists, Pattern Matching, Recursive Programming (CTM Sections 1. 1 -1. 7, 3. 2, 3. 4. 1 -3. 4. 2, 4. 7. 2) Carlos Varela RPI September 12, 2017 Adapted with permission from: Seif Haridi KTH Peter Van Roy UCL C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 1

Introduction to Oz • • • An introduction to programming concepts Declarative variables Structured

Introduction to Oz • • • An introduction to programming concepts Declarative variables Structured data (example: lists) Functions over lists Correctness and complexity C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 2

Variables • Variables are short-cuts for values, they cannot be assigned more than once

Variables • Variables are short-cuts for values, they cannot be assigned more than once declare V = 9999*9999 {Browse V*V} • Variable identifiers: is what you type • Store variable: is part of the memory system • The declare statement creates a store variable and assigns its memory address to the identifier ’V’ in the environment C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 3

Functions • Compute the factorial function: • Start with the mathematical definition declare fun

Functions • Compute the factorial function: • Start with the mathematical definition declare fun {Fact N} if N==0 then 1 else N*{Fact N-1} end • Fact is declared in the environment • Try large factorial {Browse {Fact 100}} C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 4

Factorial in Haskell factorial : : Integer -> Integer factorial 0 =1 factorial n

Factorial in Haskell factorial : : Integer -> Integer factorial 0 =1 factorial n | n > 0 = n * factorial (n-1) C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 5

Composing functions • Combinations of r items taken from n. • The number of

Composing functions • Combinations of r items taken from n. • The number of subsets of size r taken from a set of size n Comb declare fun {Comb N R} {Fact N} div ({Fact R}*{Fact N-R}) end Fact • Example of functional abstraction C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 6

Structured data (lists) • Calculate Pascal triangle • Write a function that calculates the

Structured data (lists) • Calculate Pascal triangle • Write a function that calculates the nth row as one structured value • A list is a sequence of elements: [1 4 6 4 1] • The empty list is written nil • Lists are created by means of ”|” (cons) 1 1 1 2 3 4 1 3 6 1 4 1 declare H=1 T = [2 3 4 5] {Browse H|T} % This will show [1 2 3 4 5] C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 7

Lists (2) • Taking lists apart (selecting components) • A cons has two components:

Lists (2) • Taking lists apart (selecting components) • A cons has two components: a head, and a tail declare L = [5 6 7 8] ‘|’ L. 1 gives 5 L. 2 give [6 7 8] 6 ‘|’ 7 8 C. Varela; Adapted w. permission from S. Haridi and P. Van Roy nil 8

Pattern matching • Another way to take a list apart is by use of

Pattern matching • Another way to take a list apart is by use of pattern matching with a case instruction case L of H|T then {Browse H} {Browse T} else {Browse ‘empty list’} end C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 9

Functions over lists 1 • • Compute the function {Pascal N} Takes an integer

Functions over lists 1 • • Compute the function {Pascal N} Takes an integer N, and returns the Nth row of a Pascal triangle as a list 1. For row 1, the result is [1] 2. For row N, shift to left row N-1 and shift to the right row N-1 3. Align and add the shifted rows element-wise to get row N 1 1 (0) 1 1 1 2 3 4 1 3 6 1 4 (0) 1 Shift right [0 1 3 3 1] Shift left [1 3 3 1 0] C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 10

Functions over lists (2) Pascal N declare fun {Pascal N} if N==1 then [1]

Functions over lists (2) Pascal N declare fun {Pascal N} if N==1 then [1] else {Add. List {Shift. Left {Pascal N-1}} {Shift. Right {Pascal N 1}}} end Pascal N-1 Shift. Left Shift. Right Add. List C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 11

Functions over lists (3) fun {Shift. Left L} case L of H|T then H|{Shift.

Functions over lists (3) fun {Shift. Left L} case L of H|T then H|{Shift. Left T} else [0] end fun {Shift. Right L} 0|L end fun {Add. List L 1 L 2} case L 1 of H 1|T 1 then case L 2 of H 2|T 2 then H 1+H 2|{Add. List T 1 T 2} end else nil end C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 12

Top-down program development • Understand how to solve the problem by hand • Try

Top-down program development • Understand how to solve the problem by hand • Try to solve the task by decomposing it to simpler tasks • Devise the main function (main task) in terms of suitable auxiliary functions (subtasks) that simplify the solution (Shift. Left, Shift. Right and Add. List) • Complete the solution by writing the auxiliary functions • Test your program bottom-up: auxiliary functions first. C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 13

Is your program correct? • “A program is correct when it does what we

Is your program correct? • “A program is correct when it does what we would like it to do” • In general we need to reason about the program: • Semantics for the language: a precise model of the operations of the programming language • Program specification: a definition of the output in terms of the input (usually a mathematical function or relation) • Use mathematical techniques to reason about the program, using programming language semantics C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 14

Mathematical induction • Select one or more inputs to the function • Show the

Mathematical induction • Select one or more inputs to the function • Show the program is correct for the simple cases (base cases) • Show that if the program is correct for a given case, it is then correct for the next case. • For natural numbers, the base case is either 0 or 1, and for any number n the next case is n+1 • For lists, the base case is nil, or a list with one or a few elements, and for any list T the next case is H|T C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 15

Correctness of factorial fun {Fact N} if N==0 then 1 else N*{Fact N-1} end

Correctness of factorial fun {Fact N} if N==0 then 1 else N*{Fact N-1} end • Base Case N=0: {Fact 0} returns 1 • Inductive Case N>0: {Fact N} returns N*{Fact N-1} assume {Fact N-1} is correct, from the spec we see that {Fact N} is N*{Fact N-1} C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 16

Complexity • Pascal runs very slow, declare try {Pascal 24} fun {Pascal N} •

Complexity • Pascal runs very slow, declare try {Pascal 24} fun {Pascal N} • {Pascal 20} calls: {Pascal 19} twice, if N==1 then [1] {Pascal 18} four times, {Pascal 17} else eight times, . . . , {Pascal 1} 219 times {Add. List {Shift. Left {Pascal N-1}} • Execution time of a program up to a {Shift. Right {Pascal Nconstant factor is called the program’s 1}}} time complexity. end • Time complexity of {Pascal N} is end N proportional to 2 (exponential) • Programs with exponential time complexity are impractical C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 17

Faster Pascal • • Introduce a local variable L Compute {Fast. Pascal N-1} only

Faster Pascal • • Introduce a local variable L Compute {Fast. Pascal N-1} only once Try with 30 rows. Fast. Pascal is called N times, each time a list on the average of size N/2 is processed • The time complexity is proportional to N 2 (polynomial) • Low order polynomial programs are practical. fun {Fast. Pascal N} if N==1 then [1] else local L in L={Fast. Pascal N-1} {Add. List {Shift. Left L} {Shift. Right L}} end end C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 18

Iterative computation • An iterative computation is one whose execution stack is bounded by

Iterative computation • An iterative computation is one whose execution stack is bounded by a constant, independent of the length of the computation • Iterative computation starts with an initial state S 0, and transforms the state in a number of steps until a final state Sfinal is reached: C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 19

The general scheme fun {Iterate Si} if {Is. Done Si} then Si else Si+1

The general scheme fun {Iterate Si} if {Is. Done Si} then Si else Si+1 in Si+1 = {Transform Si} {Iterate Si+1} end • Is. Done and Transform are problem dependent C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 20

The computation model • STACK : [ R={Iterate S 0}] • STACK : [

The computation model • STACK : [ R={Iterate S 0}] • STACK : [ S 1 = {Transform S 0}, R={Iterate S 1} ] • STACK : [ R={Iterate Si}] • STACK : [ Si+1 = {Transform Si}, R={Iterate Si+1} ] • STACK : [ R={Iterate Si+1}] C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 21

Newton’s method for the square root of a positive real number • Given a

Newton’s method for the square root of a positive real number • Given a real number x, start with a guess g, and improve this guess iteratively until it is accurate enough • The improved guess g’ is the average of g and x/g: C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 22

Newton’s method for the square root of a positive real number • Given a

Newton’s method for the square root of a positive real number • Given a real number x, start with a guess g, and improve this guess iteratively until it is accurate enough • The improved guess g’ is the average of g and x/g: • Accurate enough is defined as: | x – g 2 | / x < 0. 00001 C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 23

Sqrt. Iter fun {Sqrt. Iter Guess X} if {Good. Enough Guess X} then Guess

Sqrt. Iter fun {Sqrt. Iter Guess X} if {Good. Enough Guess X} then Guess else Guess 1 = {Improve Guess X} in {Sqrt. Iter Guess 1 X} end • Compare to the general scheme: – The state is the pair Guess and X – Is. Done is implemented by the procedure Good. Enough – Transform is implemented by the procedure Improve C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 24

The program version 1 fun {Sqrt X} Guess = 1. 0 in {Sqrt. Iter

The program version 1 fun {Sqrt X} Guess = 1. 0 in {Sqrt. Iter Guess X} end fun {Sqrt. Iter Guess X} if {Good. Enough Guess X} then Guess else {Sqrt. Iter {Improve Guess X} X} end fun {Improve Guess X} (Guess + X/Guess)/2. 0 end fun {Good. Enough Guess X} {Abs X - Guess*Guess}/X < 0. 00001 end C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 25

Using local procedures • The main procedure Sqrt uses the helper procedures Sqrt. Iter,

Using local procedures • The main procedure Sqrt uses the helper procedures Sqrt. Iter, Good. Enough, Improve, and Abs • Sqrt. Iter is only needed inside Sqrt • Good. Enough and Improve are only needed inside Sqrt. Iter • Abs (absolute value) is a general utility • The general idea is that helper procedures should not be visible globally, but only locally C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 26

Sqrt version 2 local fun {Sqrt. Iter Guess X} if {Good. Enough Guess X}

Sqrt version 2 local fun {Sqrt. Iter Guess X} if {Good. Enough Guess X} then Guess else {Sqrt. Iter {Improve Guess X} X} end fun {Improve Guess X} (Guess + X/Guess)/2. 0 end fun {Good. Enough Guess X} {Abs X - Guess*Guess}/X < 0. 000001 end in fun {Sqrt X} Guess = 1. 0 in {Sqrt. Iter Guess X} end C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 27

Sqrt version 3 • Define Good. Enough and Improve inside Sqrt. Iter local fun

Sqrt version 3 • Define Good. Enough and Improve inside Sqrt. Iter local fun {Sqrt. Iter Guess X} fun {Improve} (Guess + X/Guess)/2. 0 end fun {Good. Enough} {Abs X - Guess*Guess}/X < 0. 000001 end in if {Good. Enough} then Guess else {Sqrt. Iter {Improve} X} end in fun {Sqrt X} Guess = 1. 0 in {Sqrt. Iter Guess X} end C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 28

Sqrt version 3 • Define Good. Enough and Improve inside Sqrt. Iter local fun

Sqrt version 3 • Define Good. Enough and Improve inside Sqrt. Iter local fun {Sqrt. Iter Guess X} fun {Improve} (Guess + X/Guess)/2. 0 end fun {Good. Enough} {Abs X - Guess*Guess}/X < 0. 000001 end in if {Good. Enough} then Guess else {Sqrt. Iter {Improve} X} end in fun {Sqrt X} Guess = 1. 0 in {Sqrt. Iter Guess X} end The program has a single drawback: on each iteration two procedure values are created, one for Improve and one for Good. Enough C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 29

Sqrt final version fun {Sqrt X} fun {Improve Guess} (Guess + X/Guess)/2. 0 end

Sqrt final version fun {Sqrt X} fun {Improve Guess} (Guess + X/Guess)/2. 0 end The final version is fun {Good. Enough Guess} a compromise between {Abs X - Guess*Guess}/X < abstraction and efficiency 0. 000001 end fun {Sqrt. Iter Guess} if {Good. Enough Guess} then Guess else {Sqrt. Iter {Improve Guess} } end Guess = 1. 0 in {Sqrt. Iter Guess} end C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 30

From a general scheme to a control abstraction (1) fun {Iterate Si} if {Is.

From a general scheme to a control abstraction (1) fun {Iterate Si} if {Is. Done Si} then Si else Si+1 in Si+1 = {Transform Si} {Iterate Si+1} end • Is. Done and Transform are problem dependent C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 31

From a general scheme to a control abstraction (2) fun {Iterate S Is. Done

From a general scheme to a control abstraction (2) fun {Iterate S Is. Done Transform} if {Is. Done S} then S else S 1 in S 1 = {Transform S} {Iterate S 1 Is. Done Transform} end fun {Iterate Si} if {Is. Done Si} then Si else Si+1 in Si+1 = {Transform Si} {Iterate Si+1} end C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 32

Sqrt using the Iterate abstraction fun {Sqrt X} fun {Improve Guess} (Guess + X/Guess)/2.

Sqrt using the Iterate abstraction fun {Sqrt X} fun {Improve Guess} (Guess + X/Guess)/2. 0 end fun {Good. Enough Guess} {Abs X - Guess*Guess}/X < 0. 000001 end Guess = 1. 0 in {Iterate Guess Good. Enough Improve} end C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 33

Sqrt using the control abstraction fun {Sqrt X} {Iterate 1. 0 fun {$ G}

Sqrt using the control abstraction fun {Sqrt X} {Iterate 1. 0 fun {$ G} {Abs X - G*G}/X < 0. 000001 end fun {$ G} (G + X/G)/2. 0 end } end Iterate could become a linguistic abstraction C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 34

Sqrt in Haskell let sqrt x = head (drop. While (not. good. Enough) sqrt.

Sqrt in Haskell let sqrt x = head (drop. While (not. good. Enough) sqrt. Guesses) where good. Enough guess = (abs (x – guess*guess))/x < 0. 00001 improve guess = (guess + x/guess)/2. 0 sqrt. Guesses = 1: (map improve sqrt. Guesses) C. Varela; Adapted w/permission from S. Haridi and P. Van Roy 35

Exercises 12. Prove the correctness of Add. List and Shift. Left. 13. Prove that

Exercises 12. Prove the correctness of Add. List and Shift. Left. 13. Prove that the alternative version of Pascal triangle (not using Shift. Left) is correct. Make Add. List and Op. List commutative. 14. Modify the Pascal function to use local functions for Add. List, Shift. Left, Shift. Right. Think about the abstraction and efficiency tradeoffs. 15. CTM Exercise 3. 10. 2 (page 230) 16. CTM Exercise 3. 10. 3 (page 230) 17. Develop a control abstraction for iterating over a list of elements. C. Varela; Adapted w. permission from S. Haridi and P. Van Roy 36