Functions Over Lists. Programming Languages and Compilers (CS 421) Structural Recursion. Functions Over Lists. Structural Recursion : List Example

Similar documents
Programming Languages and Compilers (CS 421)

Forward Recursion. Programming Languages and Compilers (CS 421) Mapping Recursion. Forward Recursion: Examples. Folding Recursion.

# true;; - : bool = true. # false;; - : bool = false 9/10/ // = {s (5, "hi", 3.2), c 4, a 1, b 5} 9/10/2017 4

Booleans (aka Truth Values) Programming Languages and Compilers (CS 421) Booleans and Short-Circuit Evaluation. Tuples as Values.

Programming Languages and Compilers (CS 421)

n What is its running time? 9/18/17 2 n poor_rev [1,2,3] = n (poor_rev [1] = n ((poor_rev [1] =

Forward recursion. CS 321 Programming Languages. Functions calls and the stack. Functions calls and the stack

CS 321 Programming Languages

CS Lecture 6: Map and Fold. Prof. Clarkson Spring Today s music: Selections from the soundtrack to 2001: A Space Odyssey

FUNCTIONAL PROGRAMMING

Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CS Lecture 6: Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

Factorial. Next. Factorial. How does it execute? Tail recursion. How does it execute? More on recursion. Higher-order functions

Next. Tail Recursion: Factorial. How does it execute? Tail recursion. Tail recursive factorial. Tail recursive factorial.

CSci 4223 Principles of Programming Languages

Programming Languages and Compilers (CS 421)

CSc 520. Gofer III. Accumulative Recursion. Accumulative Recursion... Stack Recursion. Principles of Programming Languages. Christian Collberg

MP 2 Continuation-Passing Style

CSCI-GA Scripting Languages

School of Computer Science

Programming Languages and Compilers (CS 421)

Two Problems. Programming Languages and Compilers (CS 421) Type Inference - Example. Type Inference - Outline. Type Inference - Example

Today. Recap from last Week. Factorial. Factorial. How does it execute? How does it execute? More on recursion. Higher-order functions

CSE341: Programming Languages Lecture 6 Nested Patterns Exceptions Tail Recursion. Zach Tatlock Winter 2018

Topic 5: Examples and higher-order functions

Programming Languages and Compilers (CS 421)

Programming Languages and Compilers (CS 421)

Supplementary Notes on Concurrent ML

n Takes abstract syntax trees as input n In simple cases could be just strings n One procedure for each syntactic category

List Functions, and Higher-Order Functions

max function Next concat function max function What s the pattern? concat function More on recursion Higher-order functions

n (0 1)*1 n a*b(a*) n ((01) (10))* n You tell me n Regular expressions (equivalently, regular 10/20/ /20/16 4

Programming Languages and Compilers (CS 421)

Mobile Resource Guarantees

Continuations and Continuation-Passing Style

7.3.3 A Language With Nested Procedure Declarations

CSE341 Section 3. Standard-Library Docs, First-Class Functions, & More

SNU Programming Language Theory

A Model Of CPS Translation And Interpretation

Gain familiarity and practice with folding and mapping. The following supplementary materials may be helpful in completing this assignment:

Call-by-name evaluation

1 Announcements. 2 Scan Implementation Recap. Recitation 4 Scan, Reduction, MapCollectReduce

Haskell: From Basic to Advanced. Part 3 A Deeper Look into Laziness

Programming Languages & Compilers. Programming Languages and Compilers (CS 421) I. Major Phases of a Compiler. Programming Languages & Compilers

Programming Languages and Compilers (CS 421)

Programming Languages and Compilers (CS 421)

Continuation Passing Style. Continuation Passing Style

Playing with Fun. Walter Cazzola. Playing with Fun currying partial evaluation map&reduce iteration var args. References.

F# - LISTS. In this method, you just specify a semicolon-delimited sequence of values in square brackets. For example

OCaml. ML Flow. Complex types: Lists. Complex types: Lists. The PL for the discerning hacker. All elements must have same type.

Accurate Step Counting

FOFL and FOBS: First-Order Functions

Coq Summer School, Session 2 : Basic programming with numbers and lists. Pierre Letouzey

MoreIntro_annotated.v. MoreIntro_annotated.v. Printed by Zach Tatlock. Oct 04, 16 21:55 Page 1/10

CS3110 Spring 2016 Lecture 6: Modules

CSE 341 : Programming Languages Midterm, Spring 2015

Programming Languages & Compilers. Programming Languages and Compilers (CS 421) Programming Languages & Compilers. Major Phases of a Compiler

CS558 Programming Languages

Konzepte von Programmiersprachen

CSE 130 [Winter 2014] Programming Languages

CPS Conversion. Di Zhao.

CS 421, Fall Sample Final Questions & Solutions

Programming Languages and Compilers (CS 421)

n <exp>::= 0 1 b<exp> <exp>a n <exp>m<exp> 11/7/ /7/17 4 n Read tokens left to right (L) n Create a rightmost derivation (R)

CS422 - Programming Language Design

News. Programming Languages. Complex types: Lists. Recap: ML s Holy Trinity. CSE 130: Spring 2012

Functional Programming. Pure Functional Programming

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

Compilers: The goal. Safe. e : ASM

CS 312, Fall Exam 1

A Crash Course on Standard ML

Introduction to OCaml

About coding style Spring February 9, 2004

Today s Plan. Programming Languages. Example : Factorial. Recursion. CSE 130 : Spring Lecture 6: Higher-Order Functions

The Art of Recursion: Problem Set 10

Verification of an ML compiler. Lecture 3: Closures, closure conversion and call optimisations

COSE212: Programming Languages. Lecture 4 Recursive and Higher-Order Programming

CSCI 2041: First Class Functions

1 Introduction Closure conversion is a critical program transformation for higher-order languages that elimates lexically nested, rst-class functions

CSE 307: Principles of Programming Languages

CSE 307: Principles of Programming Languages

Introduction to Objective Caml

Why OCaml? Introduction to Objective Caml. Features of OCaml. Applications written in OCaml. Stefan Wehr

COP-5555 PROGRAMMING LANGUAGEPRINCIPLES NOTES ON RPAL

Compiler Construction Lecture 05 A Simple Stack Machine. Lent Term, Lecturer: Timothy G. Griffin. Computer Laboratory University of Cambridge

Lecture #13: Type Inference and Unification. Typing In the Language ML. Type Inference. Doing Type Inference

Preparing for Class: Watch le Videos! What is an ML program?

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

CS3110 Spring 2017 Lecture 7 Specifications using types continued

Overview. A normal-order language. Strictness. Recursion. Infinite data structures. Direct denotational semantics. Transition semantics

CSE341 Autumn 2017, Midterm Examination October 30, 2017

Recap from last time. Programming Languages. CSE 130 : Fall Lecture 3: Data Types. Put it together: a filter function

Lecture 4: Higher Order Functions

Programming Languages. Tail Recursion. CSE 130: Winter Lecture 8: NOT TR. last thing function does is a recursive call

Some Advanced ML Features

301AA - Advanced Programming

CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees. CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees 1

Lab 7: OCaml 12:00 PM, Oct 22, 2017

CS4410 : Spring 2013

Handout 2 August 25, 2008

Transcription:

Functions Over Lists Programmg Languages and Compilers (CS 421) Elsa L Gunter 2112 SC, UIUC http://courses.engr.illois.edu/cs421 Based part on slides by Mattox Beckman, as updated by Vikram Adve and Gul Agha # let rec double_up list = with [ ] -> [ ] (* pattern before ->, expression after *) (x :: xs) -> (x :: x :: double_up xs);; val double_up : 'a list -> 'a list = <fun> # let fib5_2 = double_up fib5;; val fib5_2 : t list = [8; 8; 5; 5; 3; 3; 2; 2; 1; 1; 1; 1] 9/11/17 1 9/11/17 2 Functions Over Lists Structural Recursion # let silly = double_up ["hi"; "there"];; val silly : strg list = ["hi"; "hi"; "there"; "there"] # let rec poor_rev list = with [] -> [] (x::xs) -> poor_rev xs @ [x];; val poor_rev : 'a list -> 'a list = <fun> # poor_rev silly;; - : strg list = ["there"; "there"; "hi"; "hi"] n Functions on recursive datatypes (eg lists) tend to be recursive n Recursion over recursive datatypes generally by structural recursion n Recursive calls made to components of structure of the same recursive type n Base cases of recursive types stop the recursion of the function 9/11/17 3 9/11/17 4 Structural Recursion : List Example # let rec length list = with [ ] -> 0 (* Nil case *) x :: xs -> 1 + length xs;; (* Cons case *) val length : 'a list -> t = <fun> # length [5; 4; 3; 2];; - : t = 4 n Nil case [ ] is base case n Cons case recurses on component list xs Forward Recursion n In Structural Recursion, split put to components and (eventually) recurse on components n Forward Recursion form of Structural Recursion n In forward recursion, first call the function recursively on all recursive components, and then build fal result from partial results n Wait until whole structure has been traversed to start buildg answer 9/11/17 5 9/11/17 6

Forward Recursion: Examples # let rec double_up list = with [ ] -> [ ] (x :: xs) -> (x :: x :: double_up xs);; val double_up : 'a list -> 'a list = <fun> n How do you write length with forward recursion? # let rec poor_rev list = with [] -> [] (x::xs) -> let pr = poor_rev xs pr @ [x];; val poor_rev : 'a list -> 'a list = <fun> 9/11/17 7 9/11/17 8 n How do you write length with forward recursion? match l with [] -> (a :: bs) -> n How do you write length with forward recursion? match l with [] -> (a :: bs) -> 1 + length bs 9/11/17 9 9/11/17 10 n How do you write length with forward recursion? match l with [] -> 0 (a :: bs) -> 1 + length bs Your turn now Try Problem 2 on ML2 9/11/17 11 9/11/17 12

An Important Optimization An Important Optimization Normal call h g f n When a function call is made, the return address needs to be saved to the stack so we know to where to return when the call is fished n What if f calls g and g calls h, but callg h is the last thg g does (a tail call)? Tail call h f n When a function call is made, the return address needs to be saved to the stack so we know to where to return when the call is fished n What if f calls g and g calls h, but callg h is the last thg g does (a tail call)? n Then h can return directly to f stead of g 9/11/17 13 9/11/17 14 Tail Recursion n A recursive program is tail recursive if all recursive calls are tail calls n Tail recursive programs may be optimized to be implemented as loops, thus removg the function call overhead for the recursive calls n Tail recursion generally requires extra accumulator arguments to pass partial results n May require an auxiliary function Example of Tail Recursion n Forward recursive: # let rec prod l = match l with [] -> 1 (x :: rem) -> x * prod rem;; val prod : t list -> t = <fun> n Tail recursive: # let prod list = let rec prod_aux l acc = match l with [] -> acc (y :: rest) -> prod_aux rest (acc * y) (* Uses associativity of multiplication *) prod_aux list 1;; val prod : t list -> t = <fun> 9/11/17 15 9/11/17 16 9/11/17 17 9/11/17 18

with [] -> (a :: bs) -> with [] -> n (a :: bs) -> 9/11/17 19 9/11/17 20 with [] -> n (a :: bs) -> length_aux with [] -> n (a :: bs) -> length_aux bs 9/11/17 21 9/11/17 22 with [] -> n (a :: bs) -> length_aux bs (n + 1) with [] -> n (a :: bs) -> length_aux bs (n + 1) length_aux l 0 9/11/17 23 9/11/17 24

Mappg Recursion Your turn now Try Problem 4 on MP2 n One common form of structural recursion applies a function to each element the structure # let rec doublelist list = with [ ] -> [ ] x::xs -> 2 * x :: doublelist xs;; val doublelist : t list -> t list = <fun> # doublelist [2;3;4];; - : t list = [4; 6; 8] 9/11/17 25 9/11/17 26 Mappg Functions Over Lists # let rec map f list = with [] -> [] (h::t) -> (f h) :: (map f t);; val map : ('a -> 'b) -> 'a list -> 'b list = <fun> # map plus_two fib5;; - : t list = [10; 7; 5; 4; 3; 3] # map (fun x -> x - 1) fib6;; : t list = [12; 7; 4; 2; 1; 0; 0] Mappg Recursion n Can use the higher-order recursive map function stead of direct recursion # let doublelist list = List.map (fun x -> 2 * x) list;; val doublelist : t list -> t list = <fun> # doublelist [2;3;4];; - : t list = [4; 6; 8] n Same function, but no rec 9/11/17 27 9/11/17 28 Your turn now Write a function make_app : (( a -> b) * a) list -> b list that takes a list of function put pairs and gives the result of applyg each function to its argument. Use map, no explicit recursion. let make_app l = Foldg Recursion n Another common form folds an operation over the elements of the structure # let rec multlist list = with [ ] -> 1 x::xs -> x * multlist xs;; # multlist [2;4;6];; - : t = 48 n Computes (2 * (4 * (6 * 1))) 9/11/17 29 9/11/17 30

Foldg Functions over Lists # let rec sumlist list = with [ ] -> 0 x::xs -> x + sumlist xs;; val sumlist : t list -> t = <fun> # sumlist [2;3;4];; # let rec prodlist list = with [ ] -> 1 x::xs -> x * prodlist xs;; val prodlist : t list -> t = <fun> # prodlist [2;3;4];; - : t = 24 Foldg Functions over Lists # let rec sumlist list = with [ ] -> 0 x::xs -> x + sumlist xs;; val sumlist : t list -> t = <fun> # sumlist [2;3;4];; Base Case # let rec multlist list = with [ ] -> 1 x::xs -> x * multlist xs;; # multlist [2;3;4];; - : t = 24 9/11/17 31 9/11/17 32 Foldg Functions over Lists # let rec sumlist list = with [ ] -> 0 x::xs -> x + sumlist xs;; val sumlist : t list -> t = <fun> # sumlist [2;3;4];; Recursive Call # let rec multlist list = with [ ] -> 1 x::xs -> x * multlist xs;; # multlist [2;3;4];; - : t = 24 Foldg Functions over Lists # let rec sumlist list = with [ ] -> 0 x::xs -> x + sumlist xs;; val sumlist : t list -> t = <fun> # sumlist [2;3;4];; Head Element # let rec multlist list = with [ ] -> 1 x::xs -> x * multlist xs;; # multlist [2;3;4];; - : t = 24 9/11/17 33 9/11/17 34 Foldg Functions over Lists # let rec sumlist list = with [ ] -> 0 x::xs -> x + sumlist xs;; val sumlist : t list -> t = <fun> # sumlist [2;3;4];; Combg Operation # let rec multlist list = with [ ] -> 1 x::xs -> x * multlist xs;; # multlist [2;3;4];; - : t = 24 Foldg Functions over Lists # let rec sumlist list = with [ ] -> 0 x::xs -> x + sumlist Rec value xs;; val sumlist : t list -> t = <fun> # sumlist [2;3;4];; Combg Operation # let rec multlist list = with [ ] -> 1 x::xs -> x * multlist Rec value xs;; # multlist [2;3;4];; - : t = 24R 9/11/17 35 9/11/17 36

Recursg over lists # let rec fold_right f list b = with [] -> b (x :: xs) -> f x (fold_right f xs b);; The Primitive Recursion Fairy val fold_right : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b = <fun> # fold_right (fun s -> fun () -> prt_strg s) ["hi"; "there"] ();; therehi- : unit = () Foldg Recursion n multlist folds to the right n Same as: # let multlist list = List.fold_right (fun x -> fun p -> x * p) list 1;; # multlist [2;4;6];; - : t = 48 9/11/17 37 9/11/17 38 Encodg Recursion with Fold # let rec append list1 list2 = 1 with [ ] -> list2 x::xs -> x :: append xs list2;; val append : 'a list -> 'a list -> 'a list = <fun> Base Case Operation Recursive Call # let append list1 list2 = fold_right (fun x y -> x :: y) list1 list2;; val append : 'a list -> 'a list -> 'a list = <fun> # append [1;2;3] [4;5;6];; - : t list = [1; 2; 3; 4; 5; 6] match l with [] -> 0 (a :: bs) -> 1 + length bs n How do you write length with fold_right, but no explicit recursion? 9/11/17 39 9/11/17 40 match l with [] -> 0 (a :: bs) -> 1 + length bs n How do you write length with fold_right, but no explicit recursion? let length list = List.fold_right (fun x -> fun n -> n + 1) list 0 Map from Fold # let map f list = fold_right (fun x -> fun y -> f x :: y) list [ ];; val map : ('a -> 'b) -> 'a list -> 'b list = <fun> # map ((+)1) [1;2;3];; - : t list = [2; 3; 4] n Can you write fold_right (or fold_left) with just map? How, or why not? 9/11/17 41 9/11/17 42

Iteratg over lists # let rec fold_left f a list = with [] -> a (x :: xs) -> fold_left f (f a x) xs;; val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun> # fold_left (fun () -> prt_strg) () ["hi"; "there"];; hithere- : unit = () 9/11/17 43 Encodg Tail Recursion with fold_left # let prod list = let rec prod_aux l acc = match l with [] -> acc (y :: rest) -> prod_aux rest (acc * y) prod_aux list 1;; val prod : t list -> t = <fun> Init Acc Value Recursive Call Operation # let prod list = List.fold_left (fun acc y -> acc * y) 1 list;; val prod: t list -> t = <fun> # prod [4;5;6];; - : t =120 9/11/17 44 with [] -> n (a :: bs) -> length_aux bs (n + 1) length_aux l 0 n How do you write length with fold_left, but no explicit recursion? 9/11/17 45 with [] -> n (a :: bs) -> length_aux bs (n + 1) length_aux l 0 n How do you write length with fold_left, but no explicit recursion? let length list = List.fold_left (fun n -> fun x -> n + 1) 0 list 9/11/17 46 Foldg Recall # let rec fold_left f a list = with [] -> a (x :: xs) -> fold_left f (f a x) xs;; val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun> fold_left f a [x 1 ; x 2 ; ;x n ] = f( (f (f a x 1 ) x 2 ) )x n # let rec fold_right f list b = with [ ] -> b (x :: xs) -> f x (fold_right f xs b);; val fold_right : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b = <fun> fold_right f [x 1 ; x 2 ; ;x n ] b = f x 1 (f x 2 ( (f x n b) )) # let rec poor_rev list = with [] -> [] (x::xs) -> poor_rev xs @ [x];; val poor_rev : 'a list -> 'a list = <fun> n What is its runng time? 9/11/17 47 9/11/17 48

Quadratic Time n Each step of the recursion takes time proportional to put n Each step of the recursion makes only one recursive call. n List example: # let rec poor_rev list = with [] -> [] (x::xs) -> poor_rev xs @ [x];; val poor_rev : 'a list -> 'a list = <fun> Tail Recursion - Example # let rec rev_aux list revlist = with [ ] -> revlist x :: xs -> rev_aux xs (x::revlist);; val rev_aux : 'a list -> 'a list -> 'a list = <fun> # let rev list = rev_aux list [ ];; val rev : 'a list -> 'a list = <fun> n What is its runng time? 9/11/17 49 9/11/17 50 Comparison n poor_rev [1,2,3] = n (poor_rev [2,3]) @ [1] = n ((poor_rev [3]) @ [2]) @ [1] = n (((poor_rev [ ]) @ [3]) @ [2]) @ [1] = n (([ ] @ [3]) @ [2]) @ [1]) = n ([3] @ [2]) @ [1] = n (3:: ([ ] @ [2])) @ [1] = n [3,2] @ [1] = n 3 :: ([2] @ [1]) = n 3 :: (2:: ([ ] @ [1])) = [3, 2, 1] Comparison n rev [1,2,3] = n rev_aux [1,2,3] [ ] = n rev_aux [2,3] [1] = n rev_aux [3] [2,1] = n rev_aux [ ] [3,2,1] = [3,2,1] 9/11/17 51 9/11/17 52 Foldg - Tail Recursion - # let rev list = - fold_left - (fun l -> fun x -> x :: l) //comb op [] //accumulator cell list Foldg n Can replace recursion by fold_right any forward primitive recursive defition n Primitive recursive means it only recurses on immediate subcomponents of recursive data structure n Can replace recursion by fold_left any tail primitive recursive defition 9/11/17 53 9/11/17 54

Contuation Passg Style n A programmg technique for all forms of non-local control flow: n non-local jumps n exceptions n general conversion of non-tail calls to tail calls n Essentially it s a higher-order function version of GOTO Contuations n Idea: Use functions to represent the control flow of a program n Method: Each procedure takes a function as an argument to which to pass its result; outer procedure returns no result n Function receivg the result called a contuation n Contuation acts as accumulator for work still to be done 9/11/17 55 9/11/17 56 Example of Tail Recursion # let rec app fl x = match fl with [] -> x (f :: rem_fs) -> f (app rem_fs x);; val app : ('a -> 'a) list -> 'a -> 'a = <fun> # let app fs x = let rec app_aux fl acc= match fl with [] -> acc (f :: rem_fs) -> app_aux rem_fs (fun z -> acc (f z)) app_aux fs (fun y -> y) x;; val app : ('a -> 'a) list -> 'a -> 'a = <fun> Contuation Passg Style n Writg procedures so that they take a contuation to which to give (pass) the result, and return no result, is called contuation passg style (CPS) 9/11/17 57 9/11/17 58 Example of Tail Recursion & CSP Contuation Passg Style # let app fs x = let rec app_aux fl acc= match fl with [] -> acc (f :: rem_fs) -> app_aux rem_fs (fun z -> acc (f z)) app_aux fs (fun y -> y) x;; val app : ('a -> 'a) list -> 'a -> 'a = <fun> # let rec appk fl x k = match fl with [] -> k x (f :: rem_fs) -> appk rem_fs x (fun z -> k (f z));; val appk : ('a -> 'a) list -> 'a -> ('a -> 'b) -> 'b n A compilation technique to implement nonlocal control flow, especially useful terpreters. n A formalization of non-local control flow denotational semantics n Possible termediate state compilg functional code 9/11/17 59 9/11/17 60

Terms n A function is Direct Style when it returns its result back to the caller. n A Tail Call occurs when a function returns the result of another function call without any more computations (eg tail recursion) n A function is Contuation Passg Style when it passes its result to another function. n Instead of returng the result to the caller, we pass it forward to another function. Contuation Passg Style n A compilation technique to implement nonlocal control flow, especially useful terpreters. n A formalization of non-local control flow denotational semantics n Possible termediate state compilg functional code 9/11/17 61 9/11/17 62 Example Simple Functions Takg Contuations n Simple reportg contuation: # let report x = (prt_t x; prt_newle( ) );; val report : t -> unit = <fun> n Simple function usg a contuation: # let plusk a b k = k (a + b) val plusk : t -> t -> (t -> a) -> a = <fun> # plusk 20 22 report;; 42 - : unit = () n Given a primitive operation, can convert it to pass its result forward to a contuation n Examples: # let subk x y k = k(x + y);; val subk : t -> t -> (t -> 'a) -> 'a = <fun> # let eqk x y k = k(x = y);; val eqk : 'a -> 'a -> (bool -> 'b) -> 'b = <fun> # let timesk x y k = k(x * y);; val timesk : t -> t -> (t -> 'a) -> 'a = <fun> 9/11/17 63 9/11/17 64 Nestg Contuations # let add_three x y z = x + y + z;; val add_three : t -> t -> t -> t = <fun> # let add_three x y z= let p = x + y p + z;; val add_three : t -> t -> t -> t = <fun> # let add_three_k x y z k = addk x y (fun p -> addk p z k );; val add_three_k : t -> t -> t -> (t -> 'a) -> 'a = <fun> 9/11/17 65