practice session #6: 1. sequence operations 2. partial evaluation with currying 3. lazy-lists

28
Practice session #6: 1. Sequence operations 2. Partial evaluation with currying 3. Lazy-lists

Upload: tyrone-west

Post on 02-Jan-2016

218 views

Category:

Documents


1 download

TRANSCRIPT

Practice session #6:

1. Sequence operations

2. Partial evaluation with currying

3. Lazy-lists

2

Motivation: The procedure signs maps a collection of numbers to their sign.

1. The sequence operations

For (int i=0; i<arrayLength; i++) { if (a[i] == 0) b[i] = 0 ; else b[i] = a[i]/abs(a[i]);}

In C:

Signature: signs(ls)Example: (signs(list 1 2 0 -3 4 -5 6))=> '(1 1 0 -1 1 -1 1)Type: [List(Number)->List(Number)](define signs (lambda (ls) (if (null? ls) ls (if (= 0 (car ls)) (cons 0 (signs (cdr ls)))) (cons (/ (car ls) (abs (car ls))) (signs (cdr ls)))))))

In Scheme:

3

Motivation: The procedure signs maps a collection of numbers to their sign.

1. The sequence operations

Signature: map(proc,items)Purpose: Apply 'proc' to all 'items'.Type: [[T1 -> T2]*List(T1) -> List(T2)]

The sequence operation map:

Signature: signs-map(ls)Example: (signs(list 1 2 0 -3 4 -5 6))=> '(1 1 0 -1 1 -1 1)Type: [List(Number)->List(Number)](define signs-map (lambda (ls) (map (lambda (x) (if (= x 0) 0 (/ x abs(x)))) ls)))

Implementation using sequence operations:

4

1. The sequence operations

The procedure partition divides a list into two lists according to some predicate. For example:

> (partition number? (list 1 2 ‘a 4 ‘b #t))‘((1 2 4) ‘a ‘b #t)

Implement the procedure partition, using the sequence operation filter.

The sequence operation filter:

Signature: filter(predicate, sequence)Purpose: return a list of all elements satisfying the predicate.Type:[[T-> Boolean]*List(T) -> List(T)]Post-condition: x in result <=> x in sequence, and (eq? #t (predicate x))

Additional sequence operations:

5

1. The sequence operations

The procedure partition, using the sequence operation filter:

Signature: partition(predicate, sequence)Type: [[T-> Boolean]*List(T) -> Pair(List(T),List(T))]Example: (partition number? (list 1 (cons 1 2) 3 4 (cons 0))) => '((1 3 4) (1 . 2) (0 . 3)) (partition number? (list 1 2 'a 'b 3 4 'd #t)) => '((1 2 3 4) a b d #t)

(define partition (lambda (pred seq) (cons (filter pred seq) (filter (lambda (x) (not (pred x))) seq))))

Additional sequence operations:

6

1. The sequence operations

For example:

> (accumulate + 0 (list 1 2 3 4 5))15

> (accumulate expt 1 (list 4 3 2))262144

The sequence operation accumulate:

Signature: accumulate(op,initial,sequence)Purpose: Accumulate by 'op' all sequence elements, starting (ending) with 'initial'Type: [[T1*T2 -> T2]*T2*List(T1) -> T2]Post-condition: result=(initial op (seq[n] (op ...(op seq[1]))))

4^(3^(2^1)) = 262144 ≠ 4096 = ((4^3)^2)^1

Additional sequence operations:

7

1. The sequence operations

> (define ls (list (list 1 2 3) (list 4 6 7) (list 8 9)))> (flatmap cdr ls)'(2 3 6 7 9)> (flatmap (lambda (x) (map sqr x)) ls)'(1 4 9 16 36 49 64 81)> (flatmap (lambda (lst) (filter odd? lst)) ls)'(1 3 7 9)

Signature: flatmap(proc, seq)Type:[[T1->List(T2)] * List(T1) -> List(T2)]Purpose: 1. Applies a function on every element of the given list, resulting in a new nested list. 2. Flattens the nested list (not recursively).

Question 1: flatmap

(define flatmap (lambda (proc seq) (accumulate append (list) (map proc seq))))

8

1. The sequence operations

Signature: flat-sum(ls)Type: [List -> Number]Precondition: ls is recursively made of lists and numbers only.Examples: (flat-sum '(1 2 3 (1 2 (1 (1 2 3 4) 2 3 (1 2 3 4) 4) 3 4) 4)) => 50

(flat-sum '(1 2 3 4)) => 10

Question 2: flat-sum

(define flat-sum (lambda (ls) (cond ((null? ls) 0) ((number? ls) ls) ((let ((car-sum (flat-sum (car ls))) (cdr-sum (flat-sum (cdr ls)))) (+ car-sum cdr-sum))))))

Implementation without sequence operations:

9

1. The sequence operations

Signature: flat-sum(ls)Type: [List -> Number]Precondition: ls is recursively made of lists and numbers only.Examples: (flat-sum '(1 2 3 (1 2 (1 (1 2 3 4) 2 3 (1 2 3 4) 4) 3 4) 4)) => 50

(flat-sum '(1 2 3 4)) => 10

Question 2: flat-sum

(define flat-sum (lambda (lst) (acc + 0 (map (lambda (x) (if (number? x) x (flat-sum x))) ls))))

Implementation with sequence operations:

Q: Could you think of a way to improve this Implementation?

10

1. The sequence operations

Signature: flat-sum(ls)Type: [List -> Number]Precondition: ls is recursively made of lists and numbers only.Examples: (flat-sum '(1 2 3 (1 2 (1 (1 2 3 4) 2 3 (1 2 3 4) 4) 3 4) 4)) => 50

(flat-sum '(1 2 3 4)) => 10

Question 2: flat-sum

(define flat-sum (let ((node->number (lambda (x) (if (number? x) x (flat-sum x))))) (lambda (lst) (acc + 0 (map node->number ls)))))

Implementation with sequence operations:

Q: How many closures are generated now?

11

1. The sequence operations

Signature: maximum(lst)Type: [List(Number)->Number]Pre-Condition: lst contains only natural numbers(define maximum (lambda (lst) (acc (lambda (a b) (if (> a b) a b)) 0 lst)))

Question 3: Sorting a list

Signature: insertion-sort(lst)Type: [List(Number)->List(Number)](define insertion-sort (lambda (lst) (if (null? lst) lst (let* ((max (maximum lst)) (rest (filter (lambda (x) (not (= max x))) lst))) (cons max (insertion-sort rest))))))

Implementation with sequence operations:

12

2. Partial evaluation with Currying

Signature: accumulate(op,initial,sequence)Purpose: Accumulate by ’op’ all sequence elements, starting (ending) with ’initial’Type: [[T1*T2 -> T2]*T2*LIST(T1) -> T2](define accumulate (lambda (op initial sequence) (if (null? sequence) initial (op (car sequence) (accumulate op initial (cdr sequence))))))

Question 4: Currying a recursive function - accumulate

Recall the implementation of accumulate:

Q: How would you Curry the procedure accumulate, delaying the sequence parameter?

13

2. Partial evaluation with Currying

Signature: c-accumulate-naive (op,initial)Type: [[[T*T->T]*T ->[List(T)->T]]Purpose: Partial application of accumulate (by operator and initial)(define c-accumulate-naive (lambda (op initial) (lambda (sequence) (if (null? sequence) initial (op (car sequence) ((c-accumulate-naive op initial) (cdr sequence)))))))

Question 4: Currying a recursive function - accumulate

Naïve Currying of accumulate:

14

2. Partial evaluation with Currying

Signature: c-accumulate-op-initial (op,initial)Type:[[[T*T->T]*T ->[List(T)->T]]Purpose: Partial application of accumulate (by operator and initial)(define c-accumulate-op-initial(lambda (op initial) (letrec ((iter (lambda (sequence) (if (null? sequence) initial (op (car sequence) (iter (cdr sequence))))))) iter)))

Question 4: Currying a recursive function - accumulate

A better version:

>(define add-accum (c-accumulate-op-initial + 0))>(add-accum '(1 2 3))6>(add-accum '(4 5 6))15

15

2. Partial evaluation with Currying

Signature: c-accumulate-sequence(seq)Type: [List(T)-> [[T*T->T]*T->T ]Purpose: Curried version of accumulate (by sequence)(define c-accumulate-sequence (lambda (sequence) (if (null? sequence) (lambda (op initial) initial) (let ((rest (c-accumulate-sequence (cdr sequence)))) (lambda (op initial) (op (car sequence) (rest op initial)))))))

Question 4: Currying a recursive function - accumulate

Currying by the sequence parameter:

>(define lst-accum (c-accumulate-sequence '(1 2 3)))>(lst-accum + 0)6>(lst-accum * 1)6

16

2. Partial evaluation with Currying

Signature: dists_k(ls,k)Type: [List(Number*Number) -> List(Number)]Examples: (dists_k (list (cons 3 4) (cons 3 7) (cons 15 12) (cons 3 12)) 3) => '(5 7.615773105863909 12.36931687685298)

Question 5: Using filter an map

Implement the procedure dists_k:

(define dists_k (lambda (ls k) (if (null? ls) ls (let ((xcord (caar ls)) (ycord (cdar ls)) (rest (dists_k (cdr ls) k))) (if (= xcord k) (cons (dist xcord ycord) rest) rest)))))

Implementation without sequence operations:

17

2. Partial evaluation with Currying

Signature: dists_k(ls,k)Type: [List(Number*Number) -> List(Number)]Examples: (dists_k (list (cons 3 4) (cons 3 7) (cons 15 12) (cons 3 12)) 3) => '(5 7.615773105863909 12.36931687685298)

Question 5: Using filter an map

Implement the procedure dists_k:

(define dists_k (lambda (ls k) (map (lambda (x) (dist (car x) (cdr x))) (filter (lambda (x) (= (car x) k)) ls))))

Implementation with sequence operations:

Q: Could you think of a way to improve this Implementation?

A list of pairs withX-coordinate equal to k.

18

2. Partial evaluation with Currying

Question 5: Using filter an map

(define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))

Examine the procedure dist:

(define dists_k (lambda (ls k) (map (lambda (x) (dist (car x) (cdr x))) (filter (lambda (x) (= (car x) k)) ls))))

A list of pairs withX-coordinate equal to k.

19

2. Partial evaluation with Currying

Question 5: Using filter an map

(define dist (lambda (x y) (sqrt (+ (sqr x) (sqr y)))))

Examine the procedure dist:

(define dists_k (lambda (ls k) (map (lambda (x) (dist (car x) (cdr x))) (filter (lambda (x) (= (car x) k)) ls))))

A list of pairs withX-coordinate equal to k.

(define c_dist (lambda (x) (let ((xx (sqr x))) (lambda (y) (sqrt (+ (sqr y) xx))))))

A curried version of the procedure dist:

20

2. Partial evaluation with Currying

Question 5: Using filter an map

(define dists_k (lambda (ls k) (map (lambda (x) (dist (car x) (cdr x))) (filter (lambda (x) (= (car x) k)) ls))))

A list of pairs withX-coordinate equal to k.

(define dists_k (lambda (ls k) (let ((dist_k (c_dist k))) (map (lambda (x) (dist_k (cdr x))) (filter (lambda (x) (= (car x) k)) ls)))))

New version of dists_k:

21

3. Lazy lists

Some reminders:

1. Lazy-lsits are serial data-structures that allow delayed computation.2. There is no need to store the entire list elements in memory.3. Lazy-lists may represent infinite series.4. The type of Lazy-lists is defined recursively:

LazyList = {()} union T*[Empty->LazyList]

Signature: cons(head, tail)Type: [T * [Empty->LazyList] -> LazyList]Purpose: Value constructor for lazy lists

Signature: head(lzl)Type:[LazyList -> T]Purpose: Selector for the first item of lzl (a lazy list)Pre-condition: lzl is not empty

Signature: tail(lzl)Type: [LazyList -> LazyList]Purpose: Selector for the tail (all but the first item) of lzl (a lazy list)Pre-condition: lzl is not empty

22

3. Lazy lists

Some reminders:

1. Lazy-lsits are serial data-structures that allow delayed computation.2. There is no need to store the entire list elements in memory.3. Lazy-lists may represent infinite series.4. The type of Lazy-lists is defined recursively:

LazyList = {()} union T*[Empty->LazyList]

Signature: take(lzl,n)Type: [LazyList * Number-> List]Purpose: Creates a List out of the first n items of lzl (a lazy list)Pre-condition: lzl length is at least n, n is a natural numberPost-condition: result[i]=lzl[i] for any i in range 0::n-1

Signature: nth(lzl,n)Type: [LazyList * Number-> T]Purpose: Gets the n-th item of lzl (a lazy list)Pre-condition: lzl length is at least n , n is a natural numberPost-condition: result=lzl[n-1]

23

3. Lazy lists

Examples:

Signature: integers-from(low)Purpose: Create a lazy-list containing all integers bigger than n-1 by their order.Pre-condition: n is an integer(define integers-from (lambda (n) (cons n (lambda () (integers-from (+ 1 n))))))

>(head (integers-from 5))5>(head (tail (integers-from 5)))6

24

3. Lazy lists

(define seven-boom! (lambda (n) (cons (cond ((= (modulo n 7) 0) 'boom) ((has-digit? n 7) 'boom) ((= (modulo (sum-digits? n) 7) 0) 'boom) (else n)) (lambda () (seven-boom! (+ n 1))))))

Question 6: 7-Boom

>(seven-boom! 1)‘(1 . #<procedure>)

>(take (seven-boom! 1) 7)‘(1 2 3 4 5 6 boom)

25

3. Lazy lists

Let

Question 7: Collatz conjecture

For every n>1, the sequence of numbers (n,f(f),f(f(n)),…) eventually reaches 1. For example: 563 -> 1690 -> 845 -> … 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1

(define lzl-collatz (lambda (n) (if (< n 2) (cons n (lambda () (list))) (cons n (lambda () (if (= (modulo n 2) 0) (lzl-collatz (/ n 2)) (lzl-collatz (+ (* 3 n) 1 ))))))))

> (take (lzl-collatz 563) 44)'(563 1690 845 ... 10 5 16 8 4 2 1)

26

3. Lazy lists

Question 8: lzl-filter

Signature: lzl-filter(pred lzl)Type: [[T -> Bool] * LazyList-> LazyList]Purpose: Creates a lazy list containing all members of lzl that fit the criteria pred(define lzl-filter (lambda (pred lzl) (cond ((null? lzl) lzl) ((pred (head lzl)) (cons (head lzl) (lambda () (lzl-filter pred (tail lzl))))) (else (lzl-filter pred (tail lzl))))))

> (lzl-filter (lambda (n) (= (modulo n 3) 0)) (integers-from 0))

Q: How could we generate the lazy-list of all integers that are divisible by 3?

27

3. Lazy lists

Question 8: Lazy list of prime numbers

(define primes (cons 2 (lambda () (lzl-filter prime? (integers-from 3)))))

> (take primes 6)’(2 3 5 7 11 13)

(define prime? (lambda (n) (letrec ((iter (lambda (lz) (cond ((> (sqr (head lz)) n) #t) ((divisible? n (head lz)) #f) (else (iter (tail lz))))) )) (iter primes)) ))

28

3. Lazy lists

Question 8: Lazy list of prime numbers

(define sieve (lambda (lz) (cons (head lz) (lambda () (sieve (lzl-filter (lambda (x) (not (divisible? x (head lz)))) (tail lz)))))))

(define primes1 (sieve (integers-from 2)))

> (take primes1 7)’(2 3 5 7 11 13 17)