310 likes | 474 Views
Recursion. To understand recursion , one must first understand recursion. Specifying Incremental Work. 0 -> f(0). D 1. 1 -> f(1). n -> f(n). D n. n+1 -> f(n+1). Divide and Conquer. Problem. decomposition. Subproblem1. Subproblem2. recursion. primitive.
E N D
Recursion To understand recursion, one must first understand recursion. L14Recur+Clojure
Specifying Incremental Work 0 -> f(0) D1 1 -> f(1) ... n -> f(n) Dn n+1 -> f(n+1) L14Recur
Divide and Conquer Problem decomposition Subproblem1 Subproblem2 recursion primitive Subsolution1 Subsolution2 composition Solution L14Recur
Cartesian Product > (cart2 '(1 2) '(a b)) ( (1 a) (1 b) (2 a) (2 b) ) > (cart2 '(0 1 2) '(a b)) ( (0 a) (0 b) (1 a) (1 b) (2 a) (2 b) ) > (couple ' 1 '(b c)) ( (1 b) (1 c) ) > (couple ' 1 '(a b c)) ( (1 a) (1 b) (1 c) ) L14Recur
Divide and Conquer (cart2 '(a b) '(1)) car/cdr (couple ' a '(1)) (cart2 '(b) '(1)) recursion “primitive” ((a 1)) ((b 1)) append ((a 1) (b 1)) L14Recur
Different Problems; Same pattern L14Recur
Scheme Definition (define (cart2 x y) (if (null? x) '() (append(couple (car x) y) (cart2 (cdr x) y) ) ) ) (define (couple a y) (if (null? y) '() (cons(list a (car y)) (couple a (cdr y)) ) ) ) L14Recur
Alternate Syntax : lambda (define cart2 (lambda (x y) (if (null? x) '() (append(couple (car x) y) (cart2 (cdr x) y) ) ) ) ) (define couple (lambda (a y) (if (null? y) '() (cons(list a (car y)) (couple a (cdr y)) ) ) ) ) L14Recur
Clojure Syntax (defn couple [a y] (if (empty? y) '() (cons(list a (first y)) (couple a (rest y)) ) ) ) (defn cart2 [x y] (if (empty? x) '() (concat (couple (first x) y) (cart2 (rest x) y) ) ) ) L14Recur
Powerset > (powerset '(2)) ( ( ) (2) ) > (powerset '(1 2) ) ( (1) (1 2) () (2) ) > (powerset '(0 1 2)) ( (0 1) (0 1 2) (0) (0 2) (1) (1 2) () (2) ) Subsets of {0,1,2} with 0 are equinumerous with subsets of {0,1,2} without 0. L14Recur
(define (powerset s) (if (null? s) '(()) (append (ins (car s) (powerset (cdr s)) ) (powerset (cdr s)) ) )) (define (ins a ss) (if (null? ss) '() (cons (cons a (car ss)) (ins a (cdr ss)) ) )) L14Recur
Alternate Syntax : let (define (powerset s) (if (null? s) '(()) (let ( (aux (powerset (cdr s)))) (append (ins (car s) aux) aux ) ) )) (define (ins a ss) (if (null? ss) '() (cons (cons a (car ss)) (ins a (cdr ss)) ) )) L14Recur
Clojure Syntax (defn ins [a ss] (if (empty? ss) '() (cons (cons a (first ss)) (ins a (rest ss)) ) )) (defn powerset [s] (if (empty? s) '(()) (let [aux (powerset (rest s))] (concat (ins (first s) aux) aux ) ) )) L14Recur
Related problems; Different Patterns L14Recur
Remove-First-TopLevel (define (rm-fst-top sym lis) (if (null? lis) '() (if (eq? sym (car lis))(cdrlis) (cons (car lis) (rm-fst-top sym (cdrlis)) ) ) ) ) > (rm-fst-top 'a '(b (b a) a b a)) = (b (b a) b a) • Linear recursion L14Recur
Alternate Syntax : if => cond (define (rm-fst-top sym lis) (cond ( (null? lis)'()) ( (eq? sym (car lis))(cdrlis) ) ( else (cons (car lis) (rm-fst-top sym (cdrlis)) ) ) ) ) > (rm-fst-top 'a '(b (b a) a b a)) = (b (b a) b a) • Linear recursion L14Recur
Remove-All-TopLevel (define (rm-all-top sym lis) (cond ( (null? lis)'()) ( (eq? sym (car lis)) (rm-all-top sym(cdrlis) ) ) ( else(cons (car lis) (rm-all-top sym (cdrlis))) ) ) ) > (rm-all-top 'a '(b (b a) a b a)) = (b (b a) b) > (rm-all-top ' (b a) '(b (b a) a b a)) = (b (b a) a b a) • Linear recursion L14Recur
Remove-All-Expression-TopLevel (define (rm-all-top exp lis) (cond ( (null? lis)'()) ( (equal? exp (car lis)) (rm-all-top exp(cdrlis) ) ) ( else(cons (car lis) (rm-all-top exp (cdrlis)))) ) ) > (rm-all-top ' (b a) '(b (b a) a b a)) = (b a b a) • Linear recursion L14Recur
Remove-All (define (rm-all sym ll) (cond ( (null? ll)'()) ( (symbol? (car ll)) (if (eq? sym (car ll)) ( rm-all sym (cdrll) ) ( cons (car ll) (rm-all sym (cdrll)) ) ) ) (else (cons (rm-all sym (car ll)) (rm-all sym (cdrll)) ) ) ) ) > (rm-all ' a '(b (b a) a b a)) = (b (b) b) • Double recursion L14Recur
rm-all : Structural recursion • Empty list (Basis case) (rm-all 'a '()) • First – Atom (Recursive case) (rm-all 'a '(a b c a)) (rm-all 'a '(bb c a)) • First - Nested list (Recursive case) (rm-all 'a '((a b c) d (a))) (rm-all 'a '(b (a b c) d (a))) L14Recur
Insertion sort (Note: creates a sorted copy) (define (insert n lon) (cond ((null? lon) (list n)) ((> n (car lon)) (cons (car lon) (insert n (cdr lon)))) (else (cons n lon)) ) ) (define (ins-sort lon) (if(null? lon)'() (insert (car lon) (ins-sort (cdr lon))) ) ) • Precondition: second arg to insert ordered. • Postcondition: insert returns an ordered list. L14Recur
Clojure Syntax (defn insert [n lon] (cond(empty? lon) (list n) (> n (first lon)) (cons (first lon) (insert n (rest lon))) :true (cons n lon)) ) ) (defn ins-sort [lon] (if(empty? lon)'() (insert (first lon) (ins-sort (rest lon))) ) ) • Precondition: second arg to insert ordered. • Postcondition: insert returns an ordered list. L14Recur
Subset (uses OR and AND instead of IF) (define (subset? ss s) (or (null? ss) (and (member (car ss) s) (subset? (cdr ss) s) ) ) ) 1=> (subset? '(a b c) '(A p 1 C 2 B q r)) #t 2=> (subset? '(a b c) '(p)) #f L14Recur
Anonymous functions and list membership test in Clojure > ( (fn [xy] (+ xy)) 25 30) 55 > ( #(+ %1%2) 25 30) 55 > (some #(= 5 %)'(5 30)) true > (some #(= 5 %)'(15 30)) nil L14Recur
Subset in Clojure (cf. case sensitive Scheme) (defn subset? [ss s] (or (empty? ss) (and (some #(= (first ss) %) s) (subset? (rest ss) s) ) ) ) > (subset? '() '(A p 1 C 2 B q r)) true > (subset? '(a b c) '(A p 1 C 2 B q r)) nil > (subset? '(a b c) '(p a c b)) true L14Recur
Expression evaluation :A simple syntax directed translation expr -> x | y| z expr -> (+exprexpr) expr -> (ifexprexprexpr) Write a recursive definition for a function ops that counts the number of “+”s. L14Recur
(define (ops e) ; e is assumed to be a symbol or a list (cond ((symbol? e) 0) ((eq? (car e) '+) (+ 1 (ops (cadr e)) (ops (caddr e))) ) ((eq? (car e) 'if) (+ (ops (cadr e)) (ops (caddr e)) (ops (cadddr e)))) (else (display 'ILLEGAL)) ) ) L14Recur
(defn third [x] (second (rest x))) (defn ops [e] ; Clojure code "e is assumed to be a symbol or a list" (cond (symbol? e) 0 (= (first e) '+) (+ 1 (ops (second e)) (ops (third e)) ) (= (first e) 'if) (+ (ops (second e)) (ops (third e)) (ops (last e))) true 'ILLEGAL )) L14Recur
(Alternative Scheme syntax with member and case-construct (not equivalent)) (define (ops e) ; e is assumed to be a symbol or a list (if (membere '(x y z)) 0 (if (symbol? e) (display 'ILLEGAL) (case(car e) ((+) (+ 1 (ops (cadr e)) (ops (caddr e))) ) ((if) (+ (ops (cadr e)) (ops (caddr e)) (ops (cadddr e))) ) (else (display 'ILLEGAL))) ) )) L14Recur
Examples (ops 'x) 0 (ops '(+ y z)) 1 (ops '(if x (+ y z) (+ x z))) 2 L14Recur
(Alternative syntax in Clojure (not equivalent or robust)) (defn ops [e] ;e is assumed to legal (if (some #(= e %) '(x y z)) 0 (if (symbol? e) (println 'ILLEGAL) (case (first e) (+) (+ 1 (ops (second e)) (ops (last e))) (if) (+ (ops (second e)) (ops (third e)) (ops (last e))) (println 'ILLEGAL))) ) ) L14Recur