;;; Michael Wollowski (define (rl) (load "day8.ss")) ;;; Let's have a look at three recursive functions on lists ;;; All three are very similar. ;;; All three follows the same GRAMMAR! (define sum (lambda (ls) (if (null? ls) 0 (+ (car ls) (sum (cdr ls)))))) (define product (lambda (ls) (if (null? ls) 1 (* (car ls) (product (cdr ls)))))) (define length (lambda (ls) (if (null? ls) 0 (+ 1 (length (cdr ls)))))) ;;; Let's see whether we can abstract them into one function! ;;; Let's start with abstracting the value of the base case. (define sum (lambda (ls init) (if (null? ls) init (+ (car ls) (sum (cdr ls) init))))) (define product (lambda (ls init) (if (null? ls) init (* (car ls) (product (cdr ls) init))))) (define length (lambda (ls init) (if (null? ls) init (+ 1 (length (cdr ls) init))))) ;;; All three use a binary function involving the recursive call. ;;; Let's continue by abstracting the binary function. (define list-recur (lambda (ls init f) (if (null? ls) init (f (car ls) (list-recur (cdr ls) init f))))) ;;; We now can define length, sum and product, in terms of list-recur (define sum (lambda (ls) (list-recur ls 0 +))) (define product (lambda (ls) (list-recur ls 1 *))) (define length (lambda (ls) (list-recur ls 0 (lambda (x y) (+ 1 y))))) ;;; How about some bonus functions? (define foo (lambda (ls) (list-recur ls '() (lambda (x y) (cons x y))))) (define boo (lambda (ls g) (list-recur ls '() (lambda(x y) (cons (g x) y))))) (define member-item (lambda (item ls) (list-recur ls 0 (lambda (x y) (if (eq? x item) (+ 1 y) y))))) ;;; Is 2 a member of ls? (define member2 (lambda (ls) (member-item 2 ls))) ;;; Alternate way of asking whether 2 a member of ls? (define member2 (lambda (ls) (list-recur ls 0 (lambda (x y) (if (eq? x 2) (+ 1 y) y))))) (define list-recur (lambda (init f) (letrec ([g (lambda (ls) (if (null? ls) init (f (car ls) (g (cdr ls)))))]) g))) (define sum (list-recur 0 +)) (define product (list-recur 1 *)) (define length (list-recur 0 (lambda (x y) (+ 1 y)))) (define remove-item (list-recur () (lambda (x y) (if (eq? x 2) y (cons x y))))) ;;; one one flag for all calls, once you set it, it is set. ;;; similar to static fields in Java classes ;(define remove-last-2 (list-recur () ; (let ([flag #f]) ; (lambda (x y) ; (if (and (not flag) ; (eq? x 2)) ; (begin (set! flag #t) ; y) ; (cons x y)))))) ;;; (define remove-last-2 (lambda (ls) (let ([flag #f]) ((list-recur () (lambda (x y) (if (and (not flag) (eq? x 2)) (begin (set! flag #t) y) (cons x y)))) ls)))) (define remove-last-item (lambda (item) (list-recur () (let ([flag #f]) (lambda (x y) (if (and (not flag) (eq? x 2)) (begin (set! flag #t) y) (cons x y))))))) (define list-recur-tail (lambda (init f) (letrec ([g (lambda (ls) (gTail ls init))] [gTail (lambda (ls accu) (if (null? ls) accu (gTail (cdr ls) (f (car ls) accu))))]) g))) (define remove-first-2 (list-recur '(()) (lambda (x y) (if (eq? x 2) (cons (cdr y) (cons x (cdr y))) (cons (cons x (car y)) (cons x (cdr y))))))) ;;; easier to understand (define remove-first-2 (list-recur '(()()) (lambda (x y) (if (eq? x 2) (list (cadr y) (cons x (cadr y))) (list (cons x (car y)) (cons x (cadr y))))))) ;;; final version (define remove-first-2 (lambda (ls) (car ((list-recur '(()()) (lambda (x y) (if (eq? x 2) (list (cadr y) (cons x (cadr y))) (list (cons x (car y)) (cons x (cadr y)))))) ls)))) (define double-any (list-recur () (lambda (x y) (cons x (cons x y))))) (define double-list (list-recur '(()()) (lambda (x y) (list (cons x (car y)) (cons x (cadr y))))))