A monolithic recursive solu#on A monolithic solu#on that counts up - - PowerPoint PPT Presentation

a monolithic recursive solu on a monolithic solu on that
SMART_READER_LITE
LIVE PREVIEW

A monolithic recursive solu#on A monolithic solu#on that counts up - - PowerPoint PPT Presentation

Mo#va#ng problem: ssm35 (sum-of-squares-of-multiples-of-3-or-5 n) Compositional Programming Return the sum of the squares of the all the mul#ples of 3 and 5 between 1 and n, inclusive. Since sum-of-squares-of-multiples-of-3-or-5 is a very long


slide-1
SLIDE 1

Compositional Programming

CS251 Programming Languages

Fall 2016, Lyn Turbak

Department of Computer Science Wellesley College

Mo#va#ng problem: ssm35

(sum-of-squares-of-multiples-of-3-or-5 n) Return the sum of the squares of the all the mul#ples of 3 and 5 between 1 and n, inclusive. Since sum-of-squares-of-multiples-of-3-or-5 is a very long name, we’ll abbreviate it to ssm35. For example, what should (ssm35 10) return?

2 Composition

A monolithic recursive solu#on

3 Composition

(define (ssm35-monolithic-count-down n) (if (= n 0) (if (or (divisible-by? n 3) (divisible-by? n 5)) (+ (* n n) (ssm35-monolithic-count-down (- n 1))) (ssm35-monolithic-count-down (- n 1)))))

> (ssm35-monolithic-count-down 10) 251

This starts at n, counts down to 0, and then sums up the squares of the multiples of 3 and 5

  • n the way out of the recursion.

A monolithic solu#on that counts up

4 Composition

(define (ssm35-monolithic-count-up n) (define (helper num) (if (> num n) (if (or (divisible-by? num 3) (divisible-by? num 5)) (+ (* num num) (helper (+ num 1))) (helper (+ num 1))))) (helper 1))

> (ssm35-monolithic-count-up 10) 251

This version uses a helper function to generate the numbers from 1 up to n. But it sums the squares from highest to lowest rather than lowest to highest.

slide-2
SLIDE 2

Signal-processing style of programming

5 Composition

(define (ssm35-holo n) (foldr + 0 (map (λ (x) (* x x)) (filter (λ (num) (or (divisible-by? num 3) (divisible-by? num 5))) (range 1 (+ n 1))))))

> (ssm35-holo 10) 251

This version decomposes the problem into steps that generate, map, filter, and accumulate intermediate lists. It uses higher-

  • rder list operators to manipulate the lists.

Composi#on in Racket

(define (o f g) (λ (x) (f (g x)))) (define (inc x) (+ x 1)) (define (dbl y) (* y 2)) > ((o dbl inc) 5) > ((o inc dbl) 5)

6 Composition

Composi#on style of programming

7 Composition

(define ssm35-compose (o (λ (squares) (foldr + 0 squares)) (o (λ (filtered-nums) (map (λ (x) (* x x)) filtered-nums)) (o (λ (nums) (filter (λ (num) (or (divisible-by? num 3) (divisible-by? num 5))) nums)) (o (λ (hi) (range 1 hi)) inc)))))

> (ssm35-compose 10) 251

The iden#ty func#on id

(define id (λ (x) x))) > ((o id inc) 5) > ((o dbl id) 5)

8 Composition

slide-3
SLIDE 3

Composing lists of func#ons

9 Composition

(define (o-list funlist) (foldr o id funlist)) (define (dbl x) (* x 2)) (define (inc y) (+ y 1)) (define (sq z) (* z z))

> ((o-list (list dbl inc sq)) 5)

ssm35 with o-list

10 Composition

(define ssm35-compose-list (o-list (list (λ (squares) (foldr + 0 squares)) (λ (filtered-nums) (map (λ (x) (* x x)) filtered-nums)) (λ (nums) (filter (λ (num) (or (divisible-by? num 3) (divisible-by? num 5))) nums)) (λ (hi) (range 1 hi)) inc)))

> (ssm35-compose-list 10) 251

Recall Currying

A curried binary func#on takes one argument at a #me.

(define (curry2 binop) (λ (x) (λ (y) (binop x y))) (define curried-mul (curry2 *)) > ((curried-mul 5) 4) > (my-map (curried-mul 3) (list 1 2 3)) > (my-map ((curry2 pow) 4) (list 1 2 3)) > (my-map ((curry2 (flip2 pow)) 4) (list 1 2 3)) > (define lol (list (list 2 3) (list 4) (list 5 6 7))) > (map ((curry2 cons) 8) lol) > (map (??? 8) lol) ‘((2 3 8) (4 8) (5 6 7 8)) Haskell Curry

11 Composition

Racket’s built-in curry func#on

> (((curry *) 2) 5) 10 > ((curry * 2) 5) 10 > (map (curry * 3) '(7 2 5)) '(21 6 15) > (define (triple a b c) (list a b c)) > (map (curry triple 1 2) '(7 2 5)) '((1 2 7) (1 2 2) (1 2 5)) > (map (curry triple 8 9) '(7 2 5)) '((8 9 7) (8 9 2) (8 9 5)) > (map (curry triple 8) '(7 2 5)) '(#<procedure:curried> #<procedure:curried> #<procedure:curried>)

12 Composition

slide-4
SLIDE 4

Uncurrying (no built-in Racket func#on)

> (define curried-* (curry2 *)) > (map (curried-* 3) (range 10)) '(0 3 6 9 12 15 18 21 24 27) > (define mul (uncurry2 curried-*)) > (mul 3 4) 12

13 Composition

(define (uncurry2 curried-binop) (λ (x y) ((curried-binop x) y))) (define (uncurry3 curried-ternop) (λ (x y z) (((curried-ternop x) y) z)))

Defining func#ons without any λs

14 Composition

(define map-scale (uncurry2 (o (curry2 map) (curry2 *)))) (define map-cons (uncurry2 (o (curry2 map) (curry2 cons)))) > (map-scale 5 (range 10)) '(0 5 10 15 20 25 30 35 40 45) > (map-cons 17 '((1 2 3) (4) () (5 6))) '((17 1 2 3) (17 4) (17) (17 5 6))

Some#mes argument flipping is helpful

15 Composition

(define (flip2 binop) (λ (x y) (binop y x))) > (filter ((curry2 divisible-by?) 5) (range 1 21)) '(1 5) > (filter ((curry2 (flip2 divisible-by?)) 5) (range 1 21)) '(5 10 15 20)

Handling func#ons using same arg > once

16 Composition

(define (dup-arg curried-binop) (λ (x) ((curried-binop x) x))) > ((dup-arg (curry2 *)) 5)

slide-5
SLIDE 5

and and or need special handling (why?)

17 Composition

> (((curry2 and) (> 251 100)) (divisible-by? 251 3)) and: bad syntax in: and > (((curry2 (λ (b1 b2) (and b1 b2))) (> 251 100)) (divisible-by? 251 3)) #f > (((curry2 (λ (b1 b2) (and b1 b2))) (< 251 100)) (divisible-by? 251 0)) remainder: undefined for 0

  • -and and o-or

18 Composition

(define (o-and f g) (λ (x) (and (f x) (g x)))) (define (o-or f g) (λ (x) (or (f x) (g x)))) > ((o-and (λ (n) (> n 100)) (λ (n) (divisible-by? n 3))) 251) #f > ((o-and (λ (n) (< n 100)) (λ (n) (divisible-by? n 0))) 251) #f

Defining ssm35 without any λs

19 Composition

(define ssm35-no-lambdas (o-list (list (curry foldr + 0) ((curry2 map) (dup-arg (curry2 *))) ((curry2 filter) (o-or ((curry2 (flip2 divisible-by?)) 3) ((curry2 (flip2 divisible-by?)) 5))) ((curry2 range) 1) ((curry2 +) 1))))

> (ssm35-no-lambdas 10) 251