;; CSE 413 21sp ;; Lectures 5-6: scope, let, let*; tail recursion; intro to higher-order functions #lang racket ;; From last time - first example of a local binding (local scope) ;; version 2 - local name for reversed list (define (revrev lst) (let ([r (reverse lst)]) (append r r))) ;; Scope of variables - global and local (define x 10) (define (add1 x) (+ x 1)) (define (double x) (+ x x)) (define (double-add1 x) (double (add1 x))) (define (addx n) (+ x n)) ;; let and let* ;; let bindings - all expressions are evaluated in surrounding scope (define (f1) (let ([x 1] [y 2]) (+ x y))) (define (f1g) (let ([y 2]) (+ x y))) (define (f2) (let ([x 1] [y (+ x 1)]) (+ x y))) ;; let* - each binding added to environment before evaluating next expression (define (f3) (let* ([x 1] [y (+ x 1)]) (+ x y))) (define (f4) (let* ([y (+ x 1)] [x 1]) (+ x y))) ;; recursion and applicative programming (new handout) ;; Basic rules: ;; - know when to stop (base case) ;; - decide how to take one step towards base case ;; - solution is take one step and combine with smaller version of original problem ;; Some basic patterns (from handout) ;; augmenting recursion - build up answer bit by bit ;; numeric example: n! (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) ;; list example: double each element in a list (define (double-each xs) (if (null? xs) '() (cons (* 2 (car xs)) (double-each (cdr xs))))) ;; another list example: append (define (app xs ys) (if (null? xs) ys (cons (car xs) (app (cdr xs) ys)))) ;; special subcase of augmenting recursion: reducing functions ;; reduce a list to a single result (define (sumlist xs) (if (null? xs) 0 (+ (car xs) (sumlist (cdr xs))))) ;; tail recursion ;; x contained in list? (define (contains? x lst) (cond [(null? lst) #f] [(equal? x (car lst)) #t] [else (contains? x (cdr lst))])) ; (fact 4) ; => (* 4 (fact 3)) ; => (* 4 (* 3 (fact 2))) ; => (* 4 (* 3 (* 2 (fact 1)))) ; => (* 4 (* 3 (* 2 (* 1 (fact 0))))) ; => (* 4 (* 3 (* 2 (* 1 1)))) ; => (* 4 (* 3 (* 2 1))) ; => (* 4 (* 3 2)) ; => (* 4 6) ; => 24 ; (factt 4) ; => (factaux 4 1) ; => (factaux 3 4) ; => (factaux 2 12) ; => (factaux 1 24) ; => (factaux 0 24) ; => 24 ;; n! tail-recursive (define (factt n) (factaux n 1)) ;; = n! * acc (define (factaux n acc) (if (= n 0) acc (factaux (- n 1) (* n acc)))) ;; n! with local aux function (i.e., aux function is not in global namespace) (define (factloc n) (letrec ([aux (lambda (n acc) (if (= n 0) acc (aux (- n 1) (* n acc))))]) (aux n 1))) ;; New example - tail recursive list reverse ; Ordinary reverse - O(n^2) (define (rev lst) (if (null? lst) '() (append (rev (cdr lst)) (list (car lst))))) ; tail-recursive reverse - O(n) (!) (define (revt lst) (revaux lst '())) ; = (append (rev lst) acc)) (define (revaux lst acc) (if (null? lst) acc (revaux (cdr lst) (cons (car lst) acc)))) ;; applicative (higher-order) programming and lambdas (anonymous functions) ;; some data (define abc '(a b c)) (define alist '(a (b c) d e)) (define nums '(1 2 3 4 5)) (define (dbllst lst) (if (null? lst) '() (cons (* 2 (car lst)) (dbllst (cdr lst))))) (define (incrlst lst) (if (null? lst) '() (cons (+ 1 (car lst)) (incrlst (cdr lst))))) (define (maplst f lst) (if (null? lst) '() (cons (f (car lst)) (maplst f (cdr lst))))) (define (dbl n) (* 2 n)) (define (incr n) (+ 1 n)) ;; Examples: ; (maplst dbl nums) ; (maplst incr nums) ; (maplst odd? nums) ; (maplst (lambda (n) (* n n)) nums) ; (maplst (lambda (x) (list x x)) nums) ;; filter function - return new list whose elements statisfy some predicate (define (filterlst f lst) (cond [(null? lst) '()] [(f (car lst)) (cons (car lst) (filterlst f (cdr lst)))] [else (filterlst f (cdr lst))])) ;; Examples ; (filterlst odd? nums) ; (filterlst (lambda (n) (> n 2)) nums) ;; reducing function - combine elements of list using some function (define (sumlst lst) (if (null? lst) 0 (+ (car lst) (sumlst (cdr lst))))) (define (prodlst lst) (if (null? lst) 1 (* (car lst) (prodlst (cdr lst))))) (define (reducelst op id lst) (if (null? lst) id (op (car lst) (reducelst op id (cdr lst))))) ;; Examples: ; (reducelst + 0 nums) ; (reducelst * 1 nums ;; Library version of reducelst is called foldr. There is also a ;; foldl function that does the same but with different associativity ;; Partial application and curried functions ;; ordinary addition (define add (lambda (x y) (+ x y))) ;; curried add - result is a function that can be applied to a number (define cadd (lambda (x) (lambda (y) (+ x y)))) ;; Examples: ; (add 2 3) ; ((cadd 2) 3) ; (define plus2 (cadd 2)) ; (plus2 3) ; (define plusx (cadd x)) ; global x ; (plusx 4) ; (maplst plus2 nums)