#lang racket ;; Used to redefine Racket functions in terms of the original functions (require (rename-in racket [cons racket-cons] [null? racket-null?] [eq? racket-eq?] [+ racket+] [- racket-] [number? racket-number?])) (provide (all-defined-out)) ;;********************************************************** ;; Preface ;;********************************************************** ;; [Primitive] ;; Predicate for determining if a value is an atom or not. ;; The definition of this is found in the preface. (define (atom? x) (and (not (pair? x)) (not (racket-null? x)))) ;; Note that we need to use the racket-null? and not our newly contracted null? ;; becuase x may be an atom, which racket-null? supports and null? (as defined ;; in the book and thus our contracted version) does not. ;;********************************************************** ;; Chapter 1 ;;********************************************************** ;; [Primitive] ;; Predicate for determining if a value is an S-expression or not (define (s-exp? x) (or (atom? x) (list? x))) ;; [Primitive] ;; Provide a cons as defined in the book such that it requires a list as ;; the second argument. This is enforced using Racket's contract system. ;; Racket's cons works on any values, as mentioned in the footnote on page 8. (define/contract (cons s l) (-> any/c list? list?) (racket-cons s l)) ;; [Primitive] ;; Provide a cons as defined in the book such that it requires a list as ;; the argument. See the footnote on page 10. (define/contract (null? l) (-> list? boolean?) (racket-null? l)) ;; [Primitive] ;; Provide an eq? as defined in the book such that it requires a non-numeric ;; atom for each argument. See the footnotes on page 12. (define/contract (eq? a b) (-> (and/c atom? (not/c racket-number?)) (and/c atom? (not/c racket-number?)) boolean?) (racket-eq? a b)) ;;********************************************************** ;; Chapter 2 ;;********************************************************** ;; Predicate for determining if a value is a list of atoms or not (define lat? (lambda (l) (cond [(null? l) #t] [(atom? (car l)) (lat? (cdr l))] [else #f]))) ;; Predicate for determining if a value is an element of the list of atoms or not #;(define member? (lambda (a lat) (cond [(null? lat) #f] [else (or (eq? (car lat) a) (member? a (cdr lat)))]))) ;;********************************************************** ;; Chapter 3 ;;********************************************************** ;; Removes the first occurence of the atom, if possible, in the list of atoms ;; (Rewritten below in the Chapter 5 section using equal? as instructed by the book) #;(define rember (lambda (a lat) (cond [(null? lat) '()] [(eq? a (car lat)) (cdr lat)] [else (cons (car lat) (rember a (cdr lat)))]))) ;; Takes a list and returns a list of the first elements of each sublist (define firsts (lambda (l) (cond [(null? l) '()] [else (cons (car (car l)) (firsts (cdr l)))]))) ;; Inserts new after the first occurrence, if any, of old in lat, a list of atoms ;; (Rewritten using insert-g in Chapter 8.) #;(define insertR (lambda (new old lat) (cond [(null? lat) '()] [(eq? old (car lat)) (cons old (cons new (cdr lat)))] [else (cons (car lat) (insertR new old (cdr lat)))]))) ;; Inserts new before the first occurrence, if any, of old in lat, a list of atoms ;; (Rewritten using insert-g in Chapter 8.) #;(define insertL (lambda (new old lat) (cond [(null? lat) '()] [(eq? old (car lat)) (cons new lat)] ; since (cons old (cdr lat)) = lat when old = (car lat) [else (cons (car lat) (insertL new old (cdr lat)))]))) ;; Replaces the first occurrence of old, if any, with new, in lat, a list of atoms ;; (Rewritten using insert-g in Chapter 8.) #;(define subst (lambda (new old lat) (cond [(null? lat) '()] [(eq? old (car lat)) (cons new (cdr lat))] [else (cons (car lat) (subst new old (cdr lat)))]))) ;; Replaces the first occurence of o1 or o2, if any, in lat, a list of atoms (define subst2 (lambda (new o1 o2 lat) (cond [(null? lat) '()] [(or (eq? o1 (car lat)) (eq? o2 (car lat))) (cons new (cdr lat))] [else (cons (car lat) (subst2 new o1 o2 (cdr lat)))]))) ;; Removes all occurrences of a in lat, a list of atoms #;(define multirember (lambda (a lat) (cond [(null? lat) '()] [(eq? a (car lat)) (multirember a (cdr lat))] [else (cons (car lat) (multirember a (cdr lat)))]))) ;; Inserts new after all occurrences of old in lat, a list of atoms (define multiinsertR (lambda (new old lat) (cond [(null? lat) '()] [(eq? old (car lat)) (cons old (cons new (multiinsertR new old (cdr lat))))] [else (cons (car lat) (multiinsertR new old (cdr lat)))]))) ;; Inserts new before all occurrences of old in lat, a list of atoms (define multiinsertL (lambda (new old lat) (cond [(null? lat) '()] [(eq? old (car lat)) (cons new (cons (car lat) (multiinsertL new old (cdr lat))))] ; since (cons old (cdr lat)) = lat when old = (car lat) [else (cons (car lat) (multiinsertL new old (cdr lat)))]))) ;; Replaces all occurrences of old with new in lat, a list of atoms (define multisubst (lambda (new old lat) (cond [(null? lat) '()] [(eq? old (car lat)) (cons new (multisubst new old (cdr lat)))] [else (cons (car lat) (multisubst new old (cdr lat)))]))) ;;********************************************************** ;; Chapter 4 ;;********************************************************** ;; Adds 1 to the number n (define add1 (lambda (n) (racket+ n 1))) ;; Subtracts 1 from the number n (define sub1 (lambda (n) (racket- n 1))) ;; Add two non-negative integer numbers (define + (lambda (n m) (cond [(zero? m) n] [else (+ (add1 n) (sub1 m))]))) ; I think this is more clear by adding 1 to n rather than the result ;; Subtract two non-negative integer numbers (define - (lambda (n m) (cond [(zero? m) n] [else (- (sub1 n) (sub1 m))]))) ; I think this is more clear by subtracting 1 from n rather than the result ;; [Primitive] ;; Predicate for determining if a list is a list of non-negative numbers or not (define (tup? x) (andmap exact-nonnegative-integer? x)) ;; Adds all the numbers in a tuple together (define addtup (lambda (tup) (cond [(null? tup) 0] [else (+ (car tup) (addtup (cdr tup)))]))) ;; Multiples two non-negative integer numbers (define × (lambda (n m) (cond [(zero? m) 0] [else (+ n (× n (sub1 m)))]))) ;; Adds the elements of two tuples together (define tup+ (lambda (tup1 tup2) (cond [(null? tup1) tup2] [(null? tup2) tup1] [else (cons (+ (car tup1) (car tup2)) (tup+ (cdr tup1) (cdr tup2)))]))) ;; Determines if n > m (define > (lambda (n m) (cond [(zero? n) #f] [(zero? m) #t] [else (> (sub1 n) (sub1 m))]))) ;; Determines if n < m (define < (lambda (n m) (cond [(zero? m) #f] [(zero? n) #t] [else (< (sub1 n) (sub1 m))]))) ;; Determines if two numbers are equal or not (define = (lambda (n m) (cond [(< n m) #f] [(> n m) #f] [else #t]))) ;; Computes n to the power of m (define ↑ (lambda (n m) (cond [(zero? m) 1] [else (× n (↑ n (sub1 m)))]))) ;; Computes how many times m divides n (define ÷ (lambda (n m) (cond [(< n m) 0] [else (add1 (÷ (- n m) m))]))) ;; Returns the length of lat, a list of atoms (define length (lambda (lat) (cond [(null? lat) 0] [else (add1 (length (cdr lat)))]))) ;; Picks the nth element of lat, a list of atoms (define pick (lambda (n lat) (cond [(zero? (sub1 n)) (car lat)] [else (pick (sub1 n) (cdr lat))]))) ;; Removes the nth element from lat, a list of atoms (define rempick (lambda (n lat) (cond [(one? n) (cdr lat)] [else (cons (car lat) (rempick (sub1 n) (cdr lat)))]))) ;; [Primitive] ;; Predicate for determining if a value is a numeric atom, i.e. a non-negative integer, or not (define (number? x) (exact-nonnegative-integer? x)) ;; Removes all numbers from lat, a list of atoms (define no-nums (lambda (lat) (cond [(null? lat) '()] [(number? (car lat)) (no-nums (cdr lat))] [else (cons (car lat) (no-nums (cdr lat)))]))) ;; Returns a tuple made out of all the numbers in lat, a list of atoms (define all-nums (lambda (lat) (cond [(null? lat) '()] [(number? (car lat)) (cons (car lat) (all-nums (cdr lat)))] [else (all-nums (cdr lat))]))) ;; Predicate that determines if a1 and a2 are the same number or same atom (define eqan? (lambda (a1 a2) (cond [(and (number? a1) (number? a2)) (= a1 a2)] [(or (number? a1) (number? a2)) #f] [else (eq? a1 a2)]))) ;; Counts the number of times the atom a occurs in lat, a list of atoms (define occur (lambda (a lat) (cond [(null? lat) 0] [(eq? a (car lat)) (add1 (occur a (cdr lat)))] [else (occur a (cdr lat))]))) ;; Predicate that determines if n is 1 or not (define one? (lambda (n) (= n 1))) ;;********************************************************** ;; Chapter 5 ;;********************************************************** ;; Removes the atom a everywhere it occurs the list l (define rember* (lambda (a l) (cond [(null? l) '()] [(atom? (car l)) (cond [(eq? a (car l)) (rember* a (cdr l))] [else (cons (car l) (rember* a (cdr l)))])] [else (cons (rember* a (car l)) (rember* a (cdr l)))]))) ;; Inserts new to the right of where old appears everywhere in the list l (define insertR* (lambda (new old l) (cond [(null? l) '()] [(atom? (car l)) (cond [(eq? old (car l)) (cons old (cons new (insertR* new old (cdr l))))] [else (cons (car l) (insertR* new old (cdr l)))])] [else (cons (insertR* new old (car l)) (insertR* new old (cdr l)))]))) ;; Counts how many times the atom a occurs in the list l (define occur* (lambda (a l) (cond [(null? l) 0] [(atom? (car l)) (cond [(eq? a (car l)) (add1 (occur* a (cdr l)))] [else (occur* a (cdr l))])] [else (+ (occur* a (car l)) (occur* a (cdr l)))]))) ;; Replaces old with new everywhere old appears in the list l (define subst* (lambda (new old l) (cond [(null? l) '()] [(atom? (car l)) (cond [(eq? old (car l)) (cons new (subst* new old (cdr l)))] [else (cons (car l) (subst* new old (cdr l)))])] [else (cons (subst* new old (car l)) (subst* new old (cdr l)))]))) ;; Inserts new to the left of where old appears everywhere in the list l (define insertL* (lambda (new old l) (cond [(null? l) '()] [(atom? (car l)) (cond [(eq? old (car l)) (cons new (cons old (insertL* new old (cdr l))))] [else (cons (car l) (insertL* new old (cdr l)))])] [else (cons (insertL* new old (car l)) (insertL* new old (cdr l)))]))) ;; Determines if the atom is found in the list l (define member* (lambda (a l) (cond [(null? l) #f] [(atom? (car l)) (or (eq? a (car l)) (member* a (cdr l)))] [else (or (member* a (car l)) (member* a (cdr l)))]))) ;; Returns the leftmost atom in a non-empty list (define leftmost (lambda (l) (cond [(atom? (car l)) (car l)] [else (leftmost (car l))]))) ;; Determines if the two lists are equal or not ;; (Rewritten below using equal? as instructed by the book) #;(define eqlist? (lambda (l1 l2) (cond [(and (null? l1) (null? l2)) #t] [(or (null? l1) (null? l2)) #f] [(and (atom? (car l1)) (atom? (car l2))) (and (eqan? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2)))] [(or (atom? (car l1)) (atom? (car l2))) #f] [else (and (eqlist? (car l1) (car l2)) (eqlist? (cdr l1) (cdr l2)))]))) ;; Determines if the two S-expressions are equal or not (define equal? (lambda (s1 s2) (cond [(and (atom? s1) (atom? s2)) (eqan? s1 s2)] [(or (atom? s1) (atom? s2)) #f] [else (eqlist? s1 s2)]))) ;; Determines if the two lists are equal or not (define eqlist? (lambda (l1 l2) (cond [(and (null? l1) (null? l2)) #t] [(or (null? l1) (null? l2)) #f] [else (and (equal? (car l1) (car l2)) (equal? (cdr l1) (cdr l2)))]))) ;; Removes the first occurence of the atom, if possible, in the list of atoms (define rember (lambda (s l) (cond [(null? l) '()] [(equal? s (car l)) (cdr l)] [else (cons (car l) (rember s (cdr l)))]))) ;;********************************************************** ;; Chapter 6 ;;********************************************************** ;; Determines if the arithmetic expression aexp contains only numbers besides +, ×, and ↑ #;(define numbered? (lambda (aexp) (cond [(atom? aexp) (number? aexp)] [(or (eq? (car (cdr aexp)) (quote +)) (eq? (car (cdr aexp)) (quote ×)) (eq? (car (cdr aexp)) (quote ↑))) (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))] [else #f]))) ;; Note: the book assumes aexp is already an arithmetic expression such that we don't need to test that it is ;; as this implementation does, looking for +, ×, and ↑. ;; Determines if the arithmetic expression aexp contains only numbers besides +, ×, and ↑ (define numbered? (lambda (aexp) (cond [(atom? aexp) (number? aexp)] [else (and (numbered? (car aexp)) (numbered? (car (cdr (cdr aexp)))))]))) ;; The book has two implementations of value for two different representations. ;; The value for the first representation is what is implemented here. ;; Evaluates the value of a numbered arithmetic expression #;(define value (lambda (nexp) (cond [(atom? nexp) nexp] ; Really should ask number? and not just atom? [(eq? (car (cdr nexp)) (quote +)) (+ (value (car nexp)) (value (car (cdr (cdr nexp)))))] [(eq? (car (cdr nexp)) (quote ×)) (× (value (car nexp)) (value (car (cdr (cdr nexp)))))] [(eq? (car (cdr nexp)) (quote ↑)) (↑ (value (car nexp)) (value (car (cdr (cdr nexp)))))]))) ;; Note: I'm not a fan of the book's implementation, which assumes ↑. ;; Gets the first sub-expression from an arithmetic expression (define 1st-sub-exp (lambda (aexp) (car (cdr aexp)))) ;; Gets the second sub-expression from an arithmetic expression (define 2nd-sub-exp (lambda (aexp) (car (cdr (cdr aexp))))) ;; Gets the operator from an arithmetic expression (define operator (lambda (aexp) (car aexp))) ;; Evaluates the value of a numbered arithmetic expression ;; (Rewritten using atom-to-function in Chapter 8.) #;(define value (lambda (nexp) (cond [(atom? nexp) nexp] [(eq? (operator nexp) (quote +)) (+ (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp)))] [(eq? (operator nexp) (quote ×)) (× (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp)))] [(eq? (operator nexp) (quote ↑)) (↑ (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp)))]))) ;; Note: I'm not a fan of the book's implementation, which assumes ↑. ;;********************************************************** ;; Chapter 7 ;;********************************************************** ;; Predicate for determining if a value is an element of the list of atoms or not ;; Redefined using equal? instead of eq? (define member? (lambda (a lat) (cond [(null? lat) #f] [else (or (equal? (car lat) a) (member? a (cdr lat)))]))) ;; Determines whether a list of atoms is a set or not (define set? (lambda (lat) (cond [(null? lat) #t] [(member? (car lat) (cdr lat)) #f] [else (set? (cdr lat))]))) ;; Makes a set out of a list of atoms #;(define makeset (lambda (lat) (cond [(null? lat) '()] [(member? (car lat) (cdr lat)) (makeset (cdr lat))] [else (cons (car lat) (makeset (cdr lat)))]))) ;; Removes all occurrences of a in lat, a list of atoms ;; Redefined using equal? instead of eq? (define multirember (lambda (a lat) (cond [(null? lat) '()] [(equal? a (car lat)) (multirember a (cdr lat))] [else (cons (car lat) (multirember a (cdr lat)))]))) ;; Makes a set out of a list of atoms (define makeset (lambda (lat) (cond [(null? lat) '()] [else (cons (car lat) (makeset (multirember (car lat) (makeset (cdr lat)))))]))) ;; Determines if set1 is a subset of set2 or not (define subset? (lambda (set1 set2) (cond [(null? set1) #t] [else (and (member? (car set1) set2) (subset? (cdr set1) set2))]))) ;; Determines if the two sets are equal or not (define eqset? (lambda (set1 set2) (and (subset? set1 set2) (subset? set2 set1)))) ;; Determines if the two set intersect or not (define intersect? (lambda (set1 set2) (cond [(null? set1) #t] [else (or (member? (car set1) set2) (intersect? (cdr set1) set2))]))) ;; Returns the intersection of the two sets (define intersect (lambda (set1 set2) (cond [(null? set1) '()] [(member? (car set1) set2) (cons (car set1) (intersect (cdr set1) set2))] [else (intersect (cdr set1) set2)]))) ;; Returns the union of the two sets (define union (lambda (set1 set2) (cond [(null? set1) set2] [(member? (car set1) set2) (union (cdr set1) set2)] [else (cons (car set1) (union (cdr set1) set2))]))) ;; Intersects all the sets in the list of sets (define intersectall (lambda (l-set) (cond [(null? (cdr l-set)) (car l-set)] [else (intersect (car l-set) (intersectall (cdr l-set)))]))) ;; Determines whether an S-expression is a list of only two S-expressions (define a-pair? (lambda (x) (cond [(atom? x) #f] [(null? x) #f] [(null? (cdr x)) #f] [else (and (s-exp? (car x)) (s-exp? (car (cdr x))) (null? (cdr (cdr x))))]))) ;; Returns the first S-expression of a list or pair (define first (lambda (p) (car p))) ;; Returns the second S-expression of a list or pair (define second (lambda (p) (car (cdr p)))) ;; Returns the third S-expression of a list (define third (lambda (p) (car (cdr (cdr p))))) ;; Builds a pair out of the two S-expressions (define build (lambda (s1 s2) (cons s1 (cons s2 '())))) ;; Determines whether a relation is a function or not (define fun? (lambda (rel) (set? (firsts rel)))) ;; Reverses a pair (define revpair (lambda (pair) (build (second pair) (first pair)))) ;; Reverses a relation (define revrel (lambda (rel) (cond [(null? rel) '()] [else (cons (revpair (car rel)) (revrel (cdr rel)))]))) ;; Takes a list and returns a list of the second elements of each sublist (define seconds (lambda (l) (cond [(null? l) '()] [else (cons (second (car l)) (seconds (cdr l)))]))) ;; Determines whether a function is full or not (define fullfun? (lambda (fun) (set? (seconds fun)))) ;; Determines whether a function is one-to-one or not (define one-to-one? (lambda (fun) (fun? (revrel fun)))) ;;********************************************************** ;; Chapter 8 ;;********************************************************** ;; Removes the first occurence of the atom a where (test? a) is true in the list of atoms ;; (Rewritten below as instructed by the book) #;(define rember-f (lambda (test? a l) (cond [(null? l) '()] [(test? a (car l)) (cdr l)] [else (cons (car l) (rember-f test? a (cdr l)))]))) ;; Returns a function that tests equality against the atom a (define eq?-c (lambda (a) (lambda (x) (eq? x a)))) ;; A function to test if the argument is eq? to 'salad (define eq?-salad (eq?-c 'salad)) ;; Removes the first occurence of the atom a where (test? a) is true in the list of atoms (define rember-f (lambda (test?) (lambda (a l) (cond [(null? l) '()] [(test? a (car l)) (cdr l)] [else (cons (car l) ((rember-f test?) a (cdr l)))])))) ;; Removes the first occurence of the atom a, using eq?, in the list of atoms (define rember-eq? (rember-f eq?)) ;; Inserts new before the first occurrence, if any, of old in lat, a list of atoms (define insertL-f (lambda (test?) (lambda (new old lat) (cond [(null? lat) '()] [(test? old (car lat)) (cons new lat)] ; since (cons old (cdr lat)) = lat when old = (car lat) [else (cons (car lat) ((insertL-f test?) new old (cdr lat)))])))) ;; Inserts new after the first occurrence, if any, of old in lat, a list of atoms (define insertR-f (lambda (test?) (lambda (new old lat) (cond [(null? lat) '()] [(test? old (car lat)) (cons old (cons new (cdr lat)))] [else (cons (car lat) ((insertR-f test?) new old (cdr lat)))])))) ;; Conses new onto the cons of old and l (define seqL (lambda (new old l) (cons new (cons old l)))) ;; Conses old onto the cons of new and l (define seqR (lambda (new old l) (cons old (cons new l)))) (define insert-g (lambda (seq) (lambda (new old l) (cond [(null? l) '()] [(eq? old (car l)) (seq new old (cdr l))] [else (cons (car l) ((insert-g seq) new old (cdr l)))])))) ;; Inserts new before the first occurrence, if any, of old in lat, a list of atoms (define insertL (insert-g seqL)) ;; Inserts new after the first occurrence, if any, of old in lat, a list of atoms (define insertR (insert-g seqR)) (define seqS (lambda (new old l) (cons new l))) ;; Replaces the first occurrence of old, if any, with new, in lat, a list of atoms (define subst (insert-g seqS)) (define seqrem (lambda (new old l) l)) (define yyy (lambda (a l) ((insert-g seqrem) #f a l))) ;; Takes '+, '×, and '↑ and returns +, ×, and ↑, respectively (define atom-to-function (lambda (x) (cond [(eq? x (quote +)) +] [(eq? x (quote ×)) ×] [else ↑]))) ;; Evaluates the value of a numbered arithmetic expression ;; (Rewritten below in Chapter 10) #;(define value (lambda (nexp) (cond [(atom? nexp) nexp] [else ((atom-to-function (operator nexp)) (value (1st-sub-exp nexp)) (value (2nd-sub-exp nexp)))]))) ;; Removes all occurrences of a, using test?, in lat, a list of atoms (define multirember-f (lambda (test?) (lambda (a lat) (cond [(null? lat) '()] [(test? a (car lat)) ((multirember-f test?) a (cdr lat))] [else (cons (car lat) ((multirember-f test?) a (cdr lat)))])))) ;; Removes all occurrences of a, using eq?, in lat, a list of atoms (define multirember-eq? (multirember-f eq?)) ;; A function to test if the argument is eq? to 'tuna (define eq?-tuna (eq?-c (quote tuna))) ;; Removes all occurences that pass the test test? in lat, a list of atoms (define multiremberT (lambda (test? lat) (cond [(null? lat) '()] [(test? (car lat)) (multiremberT test? (cdr lat))] [else (cons (car lat) (multiremberT test? (cdr lat)))]))) ;; Looks at every atom of lat, a list of atoms, to see whether ;; the atom is equal, using eq?, to a. Those atoms that are not ;; equal are collected in one list ls1. The atoms that are equal ;; are collected in a second list ls2. Finally, it determines the ;; value of (f ls1 ls2). (define multirember&co (lambda (a lat col) (cond [(null? lat) (col '() '())] [(eq? (car lat) a) (multirember&co a (cdr lat) (lambda (newlat seen) (col newlat (cons (car lat) seen))))] [else (multirember&co a (cdr lat) (lambda (newlat seen) (col (cons (car lat) newlat) seen)))]))) (define a-friend (lambda (x y) (null? y))) (define new-friend (lambda (newlat seen) (a-friend newlat (cons (car 'tuna) seen)))) (define latest-friend (lambda (newlat seen) (a-friend (cons 'and newlat) seen))) (define last-friend (lambda (x y) (length x))) ;; Inserts new to the left of oldL and to the right of oldR in lat, a list of atoms, ;; for every occurrence of oldL and oldR (define multiinsertLR (lambda (new oldL oldR lat) (cond [(null? lat) '()] [(eq? (car lat) oldL) (cons new (cons oldL (multiinsertLR new oldL oldR (cdr lat))))] [(eq? (car lat) oldR) (cons oldR (cons new (multiinsertLR new oldL oldR (cdr lat))))] [else (cons (car lat) (multiinsertLR new oldL oldR (cdr lat)))]))) (define multiinsertLR&co (lambda (new oldL oldR lat col) (cond [(null? lat) (col '() 0 0)] [(eq? (car lat) oldL) (multiinsertLR&co new oldL oldR (cdr lat) (lambda (newlat L R) (col (cons new (cons oldL newlat)) (add1 L) R)))] [(eq? (car lat) oldR) (multiinsertLR&co new oldL oldR (cdr lat) (lambda (newlat L R) (col (cons oldR (cons new newlat)) L (add1 R))))] [else (multiinsertLR&co new oldL oldR (cdr lat) (lambda (newlat L R) (col (cons (car lat) newlat) L R)))]))) ;; Determines whether the number is even or not (define even? (lambda (n) (= (× (÷ n 2) 2) n))) ;; Removes all odd numbers from a list of nested lists (define evens-only* (lambda (l) (cond [(null? l) '()] [(atom? (car l)) (cond [(even? (car l)) (cons (car l) (evens-only* (cdr l)))] [else (evens-only* (cdr l))])] [else (cons (evens-only* (car l)) (evens-only* (cdr l)))]))) (define evens-only*&co (lambda (l col) (cond [(null? l) (col '() 1 0)] [(atom? (car l)) (cond [(even? (car l)) (evens-only*&co (cdr l) (lambda (newl p s) (col (cons (car l) newl) (× (car l) p) s)))] [else (evens-only*&co (cdr l) (lambda (newl p s) (col newl p (+ (car l) s))))])] [else (evens-only*&co (car l) (lambda (al ap as) (evens-only*&co (cdr l) (lambda (dl dp ds) (col (cons al dl) (× ap dp) (+ as ds))))))]))) (define the-last-friend (lambda (newl product sum) (cons sum (cons product newl)))) ;;********************************************************** ;; Chapter 9 ;;********************************************************** (define looking (lambda (a lat) (keep-looking a (pick 1 lat) lat))) (define keep-looking (lambda (a sorn lat) (cond [(number? sorn) (keep-looking a (pick sorn lat) lat)] [else (eq? sorn a)]))) ;; Note: a sorn is a symbol or a number (define eternity (lambda (x) (eternity x))) ;; Takes a pair whose first component is a pair and builds a pair by ;; shifting the second part of the first component into the second ;; component (define shift (lambda (pair) (build (first (first pair)) (build (second (first pair)) (second pair))))) (define align (lambda (pora) (cond [(atom? pora) pora] [(a-pair? (first pora)) (align (shift pora))] [else (build (first pora) (align (second pora)))]))) (define length* (lambda (pora) (cond [(atom? pora) 1] [else (+ (length* (first pora)) (length* (second pora)))]))) (define weight* (lambda (pora) (cond [(atom? pora) 1] [else (+ (× (weight* (first pora)) 2) (weight* (second pora)))]))) (define shuffle (lambda (pora) (cond [(atom? pora) pora] [(a-pair? (first pora)) (shuffle (revpair pora))] [else (build (first pora) (shuffle (second pora)))]))) (define C (lambda (n) (cond [(one? n) 1] [else (cond [(even? n) (C (÷ n 2))] [else (C (add1 (× 3 n)))])]))) (define A (lambda (n m) (cond [(zero? n) (add1 m)] [(zero? m) (A (sub1 n) 1)] [else (A (sub1 n) (A n (sub1 m)))]))) (define Y (lambda (le) ((lambda (f) (f f)) (lambda (f) (le (lambda (x) ((f f) x))))))) ;;********************************************************** ;; Chapter 10 ;;********************************************************** ;; Builds an entry from a set of names and a list of values (define new-entry build) ;; Looks up the value corresponding to the name in the entry ;; and calls entry-f on name if the name is not in the entry (define lookup-in-entry (lambda (name entry entry-f) (lookup-in-entry-help name (first entry) (second entry) entry-f))) ;; Helper function for lookup-in-entry (define lookup-in-entry-help (lambda (name names values entry-f) (cond [(null? names) (entry-f name)] [(eq? (car names) name) (car values)] [else (lookup-in-entry-help name (cdr names) (cdr values) entry-f)]))) ;; Takes an entry and table and returns a new table with the ;; entry at the front (define extend-table cons) ;; Looks up the value corresponding to the name in the table, using ;; the first value found, and calls entry-f on name if the name is not ;; found in the entries listed in the table (define lookup-in-table (lambda (name table table-f) (cond [(null? table) (table-f name)] [else (lookup-in-entry name (car table) (lambda (name) (lookup-in-table name (cdr table) (table-f))))]))) ;; Converts an expression to an action (define expression-to-action (lambda (e) (cond [(atom? e) (atom-to-action e)] [else (list-to-action e)]))) ;; Converts an atom to an action (define atom-to-action (lambda (e) (cond [(number? e) *const] [(eq? e #t) *const] [(eq? e #f) *const] [(eq? e 'cons) *const] [(eq? e 'car) *const] [(eq? e 'cdr) *const] [(eq? e 'null?) *const] [(eq? e 'eq?) *const] [(eq? e 'atom?) *const] [(eq? e 'zero?) *const] [(eq? e 'add1) *const] [(eq? e 'sub1) *const] [(eq? e 'number?) *const] [else *identifier]))) ;; Converts a list to an action (define list-to-action (lambda (e) (cond [(atom? (car e)) (cond [(eq? (car e) 'quote) *quote] [(eq? (car e) 'lambda) *lambda] [(eq? (car e) 'cond) *cond] [else *application])] [else *application]))) (define value (lambda (e) (meaning e '()))) (define meaning (lambda (e table) ((expression-to-action e) e table))) (define *const (lambda (e table) (cond [(number? e) e] [(eq? e #t) #t] [(eq? e #f) #f] [else (build 'primitive e)]))) (define *quote (lambda (e table) (text-of e))) (define text-of second) (define *identifier (lambda (e table) (lookup-in-table e table initial-table))) (define initial-table (lambda (name) (car '()))) (define *lambda (lambda (e table) (build 'non-primitive (cons table (cdr e))))) (define table-of first) (define formals-of second) (define body-of third) (define evcon (lambda (lines table) (cond [(else? (question-of (car lines))) (meaning (answer-of (car lines)) table)] [(meaning (question-of (car lines)) table) (meaning (answer-of (car lines)) table)] [else (evcon (cdr lines) table)]))) (define else? (lambda (x) (cond [(atom? x) (eq? x 'else)] (else #f)))) (define question-of first) (define answer-of second) (define *cond (lambda (e table) (evcon (cond-lines-of e) table))) (define cond-lines-of cdr) (define evlis (lambda (args table) (cond [(null? args) '()] [else (cons (meaning (car args) table) (evlis (cdr args) table))]))) (define *application (lambda (e table) (apply (meaning (function-of e) table) (evlis (arguments-of e) table)))) (define function-of car) (define arguments-of cdr) (define primitive? (lambda (l) (eq? (first l) 'primitive))) (define non-primitive? (lambda (l) (eq? (first l) 'non-primitive))) (define apply (lambda (fun vals) (cond [(primitive? fun) (apply-primitive (second fun) vals)] [(non-primitive? fun) (apply-closure (second fun) vals)]))) (define apply-primitive (lambda (name vals) (cond [(eq? name 'cons) (cons (first vals) (second vals))] [(eq? name 'car) (car (first vals))] [(eq? name 'cdr) (cdr (first vals))] [(eq? name 'null?) (null? (first vals))] [(eq? name 'eq?) (eq? (first vals) (second vals))] [(eq? name 'atom?) (atom? (first vals))] [(eq? name 'add1) (add1 (first vals))] [(eq? name'sub1) (sub1 (first vals))] [(eq? name 'number?) (number? (first vals))]))) (define apply-closure (lambda (closure vals) (meaning (body-of closure) (extend-table (new-entry (formals-of closure) vals) (table-of closure))))) ;;********************************************************** ;; Tests ;;********************************************************** (module+ test (require rackunit) ;;******************************************************** ;; Primitives ;;******************************************************** (check-false (atom? (quote ()))) (check-false (atom? '())) (check-true (s-exp? '())) (check-true (s-exp? 'symbol)) (check-equal? (cons 'a '()) '(a)) (check-equal? (cons 'a '(b)) '(a b)) (check-exn exn:fail? (thunk(cons 'a 'b))) (check-pred null? '()) (check-pred null? (quote ())) (check-pred null? empty) (check-exn exn:fail? (thunk (null? 'a))) )