Fall 2018 Lecture N

Similar documents
Fall Recursion and induction. Stephen Brookes. Lecture 4

Fall Lecture 3 September 4. Stephen Brookes

Sometimes it s good to be lazy

CS 312. Lecture April Lazy Evaluation, Thunks, and Streams. Evaluation

ITERATORS AND STREAMS 9

Introduction to Functional Programming: Lecture 7 2 Functions as innite data structures Ordinary ML data structures are always nite. We can, however,

CSE341 Autumn 2017, Midterm Examination October 30, 2017

CITS3211 FUNCTIONAL PROGRAMMING. 7. Lazy evaluation and infinite lists

03-25-planned.ml Tue Mar 25 06:32: (* Lecture 14: Infinite data structures *) type a stream = Cons of a * a stream

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

News. Programming Languages. Recap. Recap: Environments. Functions. of functions: Closures. CSE 130 : Fall Lecture 5: Functions and Datatypes

PROGRAMMING IN HASKELL. CS Chapter 6 - Recursive Functions

General Computer Science (CH ) Fall 2016 SML Tutorial: Practice Problems

Lecture 3: Recursion; Structural Induction

CSE 341 Section 5. Winter 2018

Reasoning about programs. Chapter 9 of Thompson

Australian researchers develop typeface they say can boost memory, that could help students cramming for exams.

Shell CSCE 314 TAMU. Functions continued

Programming Languages

Cornell University 12 Oct Solutions. (a) [9 pts] For each of the 3 functions below, pick an appropriate type for it from the list below.

CSE341, Fall 2011, Midterm Examination October 31, 2011

Lecture 6: Sequential Sorting

Call-by-name evaluation

1 Lazy List Implementation

The Worker/Wrapper Transformation

Functional Programming. Overview. Topics. Definition n-th Fibonacci Number. Graph

Programming Languages

CSE341 Spring 2016, Midterm Examination April 29, 2016

CS153: Compilers Lecture 15: Local Optimization

The List Datatype. CSc 372. Comparative Programming Languages. 6 : Haskell Lists. Department of Computer Science University of Arizona

Functional Programming in Haskell Part 2 : Abstract dataypes and infinite structures

FUNCTIONAL PEARLS The countdown problem

Lecture 4: Higher Order Functions

CSE341, Fall 2011, Midterm Examination October 31, 2011

Practical Haskell. An introduction to functional programming. July 21, Practical Haskell. Juan Pedro Villa-Isaza. Introduction.

Induction in Coq. Nate Foster Spring 2018

02157 Functional Programming. Michael R. Ha. Sequences and Sequence Expressions. Michael R. Hansen

Option Values, Arrays, Sequences, and Lazy Evaluation

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

CSE341 Spring 2016, Midterm Examination April 29, 2016

Recursion. Tjark Weber. Functional Programming 1. Based on notes by Sven-Olof Nyström. Tjark Weber (UU) Recursion 1 / 37

Fall 2018 Lecture 7. Stephen Brookes

More fun with recursion

Processadors de Llenguatge II. Functional Paradigm. Pratt A.7 Robert Harper s SML tutorial (Sec II)

Recap: ML s Holy Trinity

CSE 341 Sample Midterm #2

Homework 3 COSE212, Fall 2018

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

GADTs. Wouter Swierstra. Advanced functional programming - Lecture 7. Faculty of Science Information and Computing Sciences

Higher-Order Functions

CSE 130 Programming Languages. Lecture 3: Datatypes. Ranjit Jhala UC San Diego

An introduction to functional programming. July 23, 2010

36 Modular Arithmetic

GADTs. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 7. [Faculty of Science Information and Computing Sciences]

Lists. Adrian Groza. Department of Computer Science Technical University of Cluj-Napoca

Problem Set CVO 103, Spring 2018

15 150: Principles of Functional Programming Sorting Integer Lists

Programming Languages Fall 2013

Recap: ML s Holy Trinity. Story So Far... CSE 130 Programming Languages. Datatypes. A function is a value! Next: functions, but remember.

CSE 130 Programming Languages. Datatypes. Ranjit Jhala UC San Diego

Advanced Type System Features Tom Schrijvers. Leuven Haskell User Group

CS 320: Concepts of Programming Languages

CSci 4223 Lecture 12 March 4, 2013 Topics: Lexical scope, dynamic scope, closures

GADTs. Alejandro Serrano. AFP Summer School. [Faculty of Science Information and Computing Sciences]

CS 340 Spring 2019 Midterm Exam

The Worker/Wrapper Transformation

Chapter 3 Programming with Recursion

CS 321 Programming Languages

CSc 372 Comparative Programming Languages

COS 326 David Walker Princeton University

Lists. Michael P. Fourman. February 2, 2010

6.037 Lecture 7B. Scheme Variants Normal Order Lazy Evaluation Streams

Recursion. Lars-Henrik Eriksson. Functional Programming 1. Based on a presentation by Tjark Weber and notes by Sven-Olof Nyström

CSE341 Spring 2017, Midterm Examination April 28, 2017

COSE212: Programming Languages. Lecture 3 Functional Programming in OCaml

CSCI-GA Final Exam

CSc 372. Comparative Programming Languages. 8 : Haskell Function Examples. Department of Computer Science University of Arizona

Inductive Data Types

Recursion and Induction

Fall Lecture 8 Stephen Brookes

Isabelle s meta-logic. p.1

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

Patterns The Essence of Functional Programming

Assigning to a Variable

15 150: Principles of Functional Programming. Exceptions

Lecture 5: Lazy Evaluation and Infinite Data Structures

Recap. Recap. If-then-else expressions. If-then-else expressions. If-then-else expressions. If-then-else expressions

CS 320 Midterm Exam. Fall 2018

15 212: Principles of Programming. Some Notes on Induction

Week 5 Tutorial Structural Induction

Testing. Wouter Swierstra and Alejandro Serrano. Advanced functional programming - Lecture 2. [Faculty of Science Information and Computing Sciences]

Programming Languages

List Functions, and Higher-Order Functions

A Second Look At ML. Chapter Seven Modern Programming Languages, 2nd ed. 1

Haskell 101. (Version 1 (July 18, 2012)) Juan Pedro Villa Isaza

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

Programming Languages

Declaring Numbers. Bernd Braßel, Frank Huch and Sebastian Fischer. Department of Computer Science, University of Kiel, Germany

SML A F unctional Functional Language Language Lecture 19

CSE 341 : Programming Languages Midterm, Spring 2015

Transcription:

15-150 Fall 2018 Lecture N Tuesday, 20 November I m too lazy to figure out the correct number Stephen Brookes

midterm2 Mean: 79.5 Std Dev: 18.4 Median: 84

today or, we could procrastinate lazy functional programming brought to you (on a plate) by

lazy programming Standard ML is call-by-value functions always evaluate their arguments Some other languages are lazy functions may defer argument evaluation until the argument value is needed You can still be lazy in a call-by-value language, but it takes effort!

being lazy Defer computation until its result is needed A function value, h : unit -> t (a thunk ) represents a delayed computation for a value of type t To compute the value, call h( ) to force the thunk

call-by-value repeat : a list -> a list fun repeat L = L @ repeat L lists are finite repeat evaluates to a function value repeat =>* (fn L => L @ repeat L) repeat [0] doesn t terminate repeat [0] =>* (fn L => L @ repeat L) [0] => [0] @ repeat [0] =>* [0] @ ([0] @ repeat [0]) =>*... forever there s no way to build an infinite list

lazy lists datatype a lazylist = a thunk Cons of a * (unit -> a lazylist) val Cons = fn - : a * (unit -> a lazylist) -> a lazylist A value of type t lazylist represents an infinite lazy list of values of type t The value has form Cons(v, h), where v : t is the head and h : unit -> t lazylist is (a thunk for) the tail the head is immediately available force h if you need later elements

lots of nothing zeros : unit -> int lazylist fun zeros ( ) = Cons(0, zeros) Zeros : int lazylist val Zeros = zeros( ) all ones ones : unit -> int lazylist fun ones ( ) = Cons(1, ones) Ones : int lazylist val Ones = ones( )

lazy naturals nats : int -> (unit -> int lazylist) fun nats n ( ) = Cons(n, nats (n+1)) Nats : int lazylist val Nats = Cons(0, nats 1) head tail { Nats represents 0,1,2,3,4,... nats 2 ( ) represents 2,3,4,5,6,...

mklazy mklazy : int list -> int lazylist fun mklazy [ ] = Zeros mklazy (x::l) = Cons(x, fn ( ) => mklazy L) Converts an int list to an int lazylist by padding with 0 s

representation A value of type t lazylist represents an infinite list of values of type t Zeros Ones nats 42 ( ) represents 0,0,0,0, represents 1,1,1,1, represents 42,43,44,45, mklazy [1,2,3] represents 1,2,3,0,0,0, An expression of type t lazylist represents if it evaluates to a value that represents

lazy append append : a list * (unit -> a lazylist) -> a lazylist fun append ([ ], h) = h( ) append (x::xs, h) = Cons(x, fn ( ) => append(xs, h)) What does append([0,1], nats 2) represent? append([0,1], nats 2) =>* Cons(0, h1) where h1( ) =>* Cons(1, h2) and h2( ) =>* Cons(2, h3) and so on append([0,1], nats 2) represents 0,1,2,3,4,

think thunks We said append([0,1], nats 2) =>* Cons(0, h1) where h1( ) =>* Cons(1, h2) It s not true that append([0,1], nats 2) =>* Cons(0, fn ( ) => Cons(1, h2)) That s not how ML works! No evaluation inside a function body.

lazy append If h( ) represents y0,y1,y2,y3, then append ([x0,,xk], h) represents x0,,xk,y0,y1,y2,y3,

repeat repeat : a list -> a lazylist REQUIRES xs [ ] ENSURES repeat(xs) represents xs repeated over and over fun repeat xs = append(xs, fn ( ) => repeat xs) repeat [0] =>*???

repeat [0] repeat [0] =>* Cons(0, h0) where h0( ) =>* Cons(0, h1) and h1( ) =>* Cons(0, h2) and so on repeat [0] represents 0,0,0,0,0,...

show show : int -> a lazylist -> a list fun show 0 _ = [ ] show n (Cons(x, h)) = x :: show (n-1) (h( )) show 5 (repeat [0]) evaluates to [0,0,0,0,0]

lazy equality Lazy list values A and B are equal iff they represent the same infinite sequence For all n, show n A = show n B. Lazy list expressions are equal if they both fail to terminate, or raise the same exception or they evaluate to equal values

lazy map map : ( a -> b) -> a lazylist -> b lazylist fun map f (Cons(x, h)) = Cons(f x, fn ( ) => map f (h( ))) map (fn x => x+1) Zeros??? If f is total and L represents x0,x1,x2, recursive call is deferred then map f L represents f(x0),f(x1),f(x2),

map is lazy List.map If f : t -> t is total, then for all L : t lazylist, and all n 0, show n (map f L) = List.map f (show n L) PROOF? Use induction on n map f (Cons(x, h)) = Cons(f x, fn ( ) => map f (h( ))) List.map f (x::xs) = (f x) :: List.map f xs show 0 _ = [ ] show n (Cons(x, h)) = x :: show (n-1) (h( ))

map is lazy List.map P(n): For all L : t lazylist, all total f, show n (map f L) = List.map f (show n L) THEOREM n 0. P(n) PROOF By induction on n Base: n=0. Both sides are [ ]. Inductive step: n > 0. We show that P(n-1) implies P(n). add justifications for the proof steps Assume IH: P(n-1). Let L be Cons(x, h) and v = f x. show n (map f L) = show n (map f (Cons(x, h))) = show n (Cons(f x, fn () => map f (h()))) = show n (Cons(v, fn () => map f (h()))) = v :: show (n-1) (map f (h())) = v :: List.map f (show (n-1) (h())) = List.map f (x ::(show (n-1) (h()))) = List.map f (show n (Cons(x, h))) = List.map f (show n L) So P(n) holds.

lazy map fusion If f and g are total and composable, then for all suitably typed lazy lists L, map (f o g) L = map f (map g L) same as map (f o g) = (map f) o (map g)

eager map eager_map : ( a -> b) -> a lazylist -> b lazylist fun eager_map f (Cons(x, h)) = let val L = eager_map f (h( )) in Cons(f x, fn ( ) => L) end eager_map (fn x => x+x) Ones???

lazy zip zip : a lazylist * b lazylist -> ( a * b) lazylist fun zip (Cons(x, h), Cons(y, k)) = Cons((x,y), fn ( ) => zip (h( ), k( ))) recursive call is deferred If A represents a0,a1,a2, and B represents b0,b1,b2, then zip(a,b) represents (a0,b0),(a1,b1),(a2,b2),

zip is lazy List.zip For all A : t1 lazylist and B : t2 lazylist and all n 0, show n (zip (A, B)) = List.zip (show n A, show n B) PROOF? Use induction on n zip (Cons(x, h), Cons(y, k)) = Cons((x, y), fn ( ) => zip (h( ), k( ))) List.zip (x::xs, y::ys) = (x, y) :: List.zip (xs, ys) show 0 _ = [ ] show n (Cons(x, h)) = x :: show (n-1) (h( ))

lazy filter filter : ( a -> bool) -> a lazylist -> a lazylist fun filter p (Cons(x, h)) = if p x then Cons(x, fn ( ) => filter p (h( ))) else filter p (h( )) if x doesn t satisfy p, filter the tail if x satisfies p, x is head of filtered list, defer filtering tail until needed

example fun nats n = Cons(n, fn ( ) => nats (n+1)) val Evens = filter (fn x => (x mod 2 = 0)) (nats 0) show 1 Evens = [0] show 2 Evens = [0,2] show 3 Evens = [0,2,4] show 4 Evens = [0,2,4,6] show 5 Evens = [0,2,4,6,8] Evens represents 0,2,4,6,8,10,. the lazy list of all non-negative even integers

warning What happens when we evaluate filter (fn x => x<0) (repeat [1])?

specification If p is total, L represents a0,a1,a2, and infinitely many ai satisfy p then filter p L represents the lazy list of all the ai that satisfy p For all n 0 there is an N such that show N (filter p L) = the first n elements of L that satisfy p

recursive laziness Some lazy lists can be generated recursively natural numbers factorials primes Fibonacci

fun facts facts : unit -> int lazylist fun facts( ) = Cons(1, fn ( ) => map (op * ) (zip (facts( ), nats 2 ( )))) facts( ) represents 1, 2, 6, 24, 120, For all n 1, show n (facts( )) = [1!,, n!]

lazy stuff To show the power of laziness we tackle some problems that build and manipulate infinite data prime number generation digitwise real arithmetic

Primes sift : int -> int lazylist -> int lazylist fun sift x = filter (fn y => y mod x <> 0) sieve : int lazylist -> int lazylist fun sieve (Cons(x, h)) = Cons(x, fn ( ) => sieve (sift x (h( )))) Primes : int lazylist val Primes = sieve(nats 2 ( )) Strike out the twos Strike out the threes...the Sieve of Eratosthenes

sift and sieve Suppose Cons(x, h) represents the integers 2 not divisible by the first n primes Then x is the n+1 th prime And sift x (h( )) represents the integers 2 not divisible by the first n+1 primes So sieve(nats 2 ( )) represents the primes

reals in decimal Can represent a real number in decimal d0.d1d2...dn... d0 = the integer part 0 dn 9 for n>0 The lazy list d 0, d 1, d2,..., d n,... represents the real number d 0 + (0.1)d 1 + (0.1) 2 d 2 + + (0.1) n d n +

eval10 eval10 : int list -> real fun eval10 [ ] = 0.0 eval10 (x::xs) = real x + 0.1 * eval10 xs eval10 [d 0, d 1, d2,..., d n ] = d 0 + (0.1)d 1 + (0.1) 2 d 2 + + (0.1) n d n

approx10 approx10 : int -> int lazylist -> real fun approx10 n L = eval10 (show (n+1) L) If L represents d 0, d 1, d2..., d n,... then approx10 n L represents d 0 + (0.1)d 1 + (0.1) 2 d 2 + + (0.1) n d n

representing reals L : int lazylist represents r : real if limn (approx10 n L) = r fun zeros( ) = Cons(0, zeros) fun nines( ) = Cons(9, nines) Cons(1, zeros) represents 1.0 Cons(0, nines) represents 1.0

validity A lazy list L is valid (decimal) iff all digits in the tail of L are between 0 and 9 Every real number has a valid representation not unique may also have invalid representations 0, 9, 0, 99, 0, 99,... 0, 9, 9, 9, 9, 9,... 1, 0, 0, 0, 0, 0,... invalid valid valid 3 lazy lists, each representing 1.0 : real

normality To do lazy real arithmetic, we need ways to build and maintain valid representations carry10 : int lazylist -> int lazylist norm10 : int lazylist -> int lazylist carry10 makes the next digit between 0 and 9 n = 10 * (n div 10) + (n mod 10) 0 n mod 10 9 norm10 makes all digits between 0 and 9, lazily without changing the real number

carry10 carry10 : int lazylist -> int lazylist REQUIRES L represents r, digits in tail of L 0 ENSURES carry10(l) represents r, has first tail digit between 0 and 9 fun carry10 (Cons(x, xs)) = let val (Cons(y, ys)) = xs( ) in Cons(x + y div 10, fn ( ) => Cons(y mod 10, ys)) end

example L 0, 10, 2, 12, 4, 14, 6,... carry10 L 1, 0, 2, 12, 4, 14, 6,... carry10 (Cons(1, zeros)) = Cons(1, zeros) carry10 (Cons(0, nines)) = Cons(0, nines)

norm10 norm10 : int lazylist -> int lazylist REQUIRES L represents r, digits in tail of L between 0 and 18 carry amount 1 ENSURES norm10(l) represents r, all digits in tail are between 0 and 9 fun norm10 (Cons(x, xs)) = let val Cons(y, ys) = xs( ) val N = Cons(x, fn ( ) => norm10 (Cons(y, ys))) in if y+1 < 10 then N else carry10 N end carry amount 1

add10 add10 : int lazylist * int lazylist -> int lazylist REQUIRES A represents a, B represents b, digits in tail of A & tail of B are decimal ENSURES add10(a,b) represents a+b, digits in tail are decimal fun add10(a, B) = norm10 (map (op +) (zip(a, B)))

example 0.123456790123456790... + 0.909090909090909090... 1.032547699214365881... val Y = repeat [0,1,2,3,4,5,6,7,9]; val Z = repeat [0,9]; show 9 (add10(y, Z)); val it = [1,0,3,2,5,4,7,6,9] : int list

lessons Reasoning about lazy data is not leisure Need to be careful about termination use specs involving show n for equational reasoning, use lazy notion of equality