Compare commits

..

No commits in common. "6fb03cda1c299ee674daff468cd1c06d369d369c" and "2a278157adeed91d716f4c0fc55df484d3b79d2f" have entirely different histories.

113 changed files with 0 additions and 706 deletions

View file

@ -1,7 +0,0 @@
(list 'a 'b 'c) -> (a b c)
(list (list 'george)) -> ((george))
(cdr '((x1 x2) (y1 y2))) -> ((y1 y2))
(cadr '((x1 x2) (y1 y2))) -> (y1 y2)
(pair? (car '(a short list))) -> #f
(memq 'red '((red shoes) (blue socks))) -> #f
(memq 'red '(red shoes blue socks)) -> (red shoes blue socks)

View file

@ -1,8 +0,0 @@
#lang sicp
(define (equal? a b)
(cond ((and (pair? a) (pair? b))
(and (equal? (car a) (car b)) (equal? (cdr a) (cdr b))))
((and (not (pair? a)) (not (pair? b)))
(and (eq? a b)))
(else #f)))

View file

@ -1,6 +0,0 @@
When typing (car ''abracadabra), the interpreter will transform the expression
into: (car (quote (quote abracadabra))), then it will evaluate.
First the symbol car becomes the car procedure, then quote gets evaluated as a
special form, which means the surrounded expression should be left
unevaluated, so we get something like: (#<car:procedure> (quote abracadabra)),
now car gets applied, and we get the expected result.

View file

@ -1,78 +0,0 @@
#lang sicp
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (=number? exp num) (and (number? exp) (= exp num)))
(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2))
(+ a1 a2))
(else (list '+ a1 a2))))
(define (make-product m1 m2)
(cond ((or (=number? m1 0) (=number? m2 0)) 0)
((=number? m1 1) m2)
((=number? m2 1) m1)
((and (number? m1) (number? m2)) (* m1 m2))
(else (list '* m1 m2))))
(define (sum? x) (and (pair? x) (eq? (car x) '+)))
(define (addend s) (cadr s))
(define (augend s) (caddr s))
(define (product? x) (and (pair? x) (eq? (car x) '*)))
(define (multiplier p) (cadr p))
(define (multiplicand p) (caddr p))
; for the purposes of our exponentiation exercise, we need to determine whether
; the exponent is constant so that we can apply the rule correctly
(define (constant? x var)
(or (number? x)
(and (variable? x) (not (same-variable? x var)))
(and (sum? x)
(constant? (addend x) var)
(constant? (augend x) var))
(and (product? x)
(constant? (multiplier x) var)
(constant? (multiplicand x) var))
(and (exponentiation? x)
(constant? (base x) var)
(constant? (exponent x) var))))
(define (make-exponentiation b e)
(cond ((=number? e 0) 1)
((=number? e 1) b)
((=number? b 0) 0)
((and (number? b) (number? e)) (expt b e))
(else (list '** b e))))
(define (exponentiation? x) (and (pair? x) (eq? (car x) '**)))
(define (base e) (cadr e))
(define (exponent e) (caddr e))
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp) (if (same-variable? exp var) 1 0))
((sum? exp) (make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
((exponentiation? exp)
(if (constant? (exponent exp) var)
(make-product (make-product (exponent exp)
(make-exponentiation (base exp)
(make-sum
(exponent exp)
-1)))
(deriv (base exp) var))
(error "non-constant exponents not yet supported: DERIV" exp)))
(else
(error "unknown expression type: DERIV" exp))))

View file

@ -1,120 +0,0 @@
#lang sicp
; For these exercises, where I'm adding extra functionality to the deriv
; system. I chose to build each new feature off of the results of the previous
; exercises, rather than the unmodified code.
; This might make the solutions a bit more complicated than they have to be
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (=number? exp num) (and (number? exp) (= exp num)))
(define (not-number? x) (not (number? x)))
(define (filter predicate sequence)
(cond ((null? sequence) nil)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
; folds the constants of the top-level expression
; e.g. (+ 2 3 x 5) becomes (+ 10 x)
; (+ x y z) -> (+ x y z)
; (* 2 x 0 3) -> 0
; (+ 3 -3 x) -> x
(define (fold exp)
(if (and (not (sum? exp)) (not (product? exp)))
exp ; if you don't know how to fold the exp, just leave it
(let* ((op (car exp))
(consts (filter number? (cdr exp)))
(rest (filter not-number? (cdr exp)))
(folded-const (if (eq? op '+)
(apply + consts)
(apply * consts)))
(args (cond ((and (eq? op '*) (= folded-const 0)) '(0))
((and (eq? op '*) (= folded-const 1)) rest)
((and (eq? op '+) (= folded-const 0)) rest)
(else (append (list folded-const) rest)))))
(cond ((and (eq? op '+) (= (length args) 0)) 0)
((and (eq? op '*) (= (length args) 0)) 1)
((= (length args) 1) (car args))
(else (append (list op) args))))))
; make-sum and make-product will be changed so that any arguments which are
; sums themselves will be spliced into the list, and all numbers will be placed
; in the front and folded
(define (make-sum a1 a2)
; l1 and l2 are lists to be spliced, if they're not sums, we make them lists
; of a list, so effectively, they don't get spliced
(let ((l1 (if (sum? a1) (cdr a1) (list a1)))
(l2 (if (sum? a2) (cdr a2) (list a2))))
(fold (append '(+) l1 l2))))
(define (make-product m1 m2)
(let ((l1 (if (product? m1) (cdr m1) (list m1)))
(l2 (if (product? m2) (cdr m2) (list m2))))
(fold (append '(*) l1 l2))))
(define (sum? x) (and (pair? x) (eq? (car x) '+)))
(define (addend s) (cadr s))
(define (augend s) (if (= (length s) 3)
(caddr s)
(cons '+ (cddr s))))
(define (product? x) (and (pair? x) (eq? (car x) '*)))
(define (multiplier p) (cadr p))
(define (multiplicand p) (if (= (length p) 3)
(caddr p)
(cons '* (cddr p))))
; for the purposes of our exponentiation exercise, we need to determine whether
; the exponent is constant so that we can apply the rule correctly
(define (constant? x var)
(or (number? x)
(and (variable? x) (not (same-variable? x var)))
(and (sum? x)
(constant? (addend x) var)
(constant? (augend x) var))
(and (product? x)
(constant? (multiplier x) var)
(constant? (multiplicand x) var))
(and (exponentiation? x)
(constant? (base x) var)
(constant? (exponent x) var))))
(define (make-exponentiation b e)
(cond ((=number? e 0) 1)
((=number? e 1) b)
((=number? b 0) 0)
((and (number? b) (number? e)) (expt b e))
(else (list '** b e))))
(define (exponentiation? x) (and (pair? x) (eq? (car x) '**)))
(define (base e) (cadr e))
(define (exponent e) (caddr e))
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp) (if (same-variable? exp var) 1 0))
((sum? exp) (make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
((exponentiation? exp)
(if (constant? (exponent exp) var)
(make-product (make-product (exponent exp)
(make-exponentiation (base exp)
(make-sum
(exponent exp)
-1)))
(deriv (base exp) var))
(error "non-constant exponents not yet supported: DERIV" exp)))
(else
(error "unknown expression type: DERIV" exp))))

View file

@ -1,272 +0,0 @@
#lang sicp
; Thoughts before the exercise:
; The first thing that I think might be an issue here is unnecessarily nested
; expressions:
; example: (((1 + 2 * 3))). We didn't have to think about these when we were simply
; using Lisp notation, since every list was basically guarranteed to have an
; operator. In our new case, every list with a length > 1 is going to have to
; have an operator, but we need a way to deal naturally with expressions of the
; form (x), where the result of the expression is obviously x.
; One idea would be to have a function that tries to access the innermost list.
; And then use it throughout all the other functions. But this would be quite
; painful. A better idea might be to consider this list to be a new kind of
; expression, called a grouping, we could have a predicate "grouping?", a
; selector "group-mem", and a constructor "group" (but there's no reason to ever
; use the constructor.)
; Okay, once we know how to deal with those, everything else should be clear: a
; sum is simply a list that contains +, a product is a list that contains * but
; not +, an exponentiation is a list which contains only the ** operator
; (speaking at the top level for all of these, of course).
; It's clear how to construct a sum, it's also clear how to get the addend and
; augend, and construction, in essence, is not complicated. However, if we want
; to try and keep the expressions somewhat simplified, like we did in previous
; exercises, we may need to do more work on the constructors.
(define op-order '(+ * **))
(define (list-index lst elem)
(define (li-rec lst elem index)
(cond ((null? lst) -1)
((eq? (car lst) elem) index)
(else (li-rec (cdr lst) elem (+ index 1)))))
(li-rec lst elem 0))
;compares precedence of ops
(define (lower-or-eq-op op1 op2)
(<= (list-index op-order op1)
(list-index op-order op2)))
; finds the-top-level op for an expression list:
; e.g. (1 + (2 * 4) * 3) => +
(define (top-op exp)
(define (top-op-rec exp op-order)
(cond ((null? op-order) nil)
((memq (car op-order) exp) (car op-order))
(else (top-op-rec exp (cdr op-order)))))
(top-op-rec exp op-order))
(define (make-group exp)
(list exp))
; a group is just a list of length 1
(define (group? exp)
(and (pair? exp) (null? (cdr exp))))
(define (degroup exp)
(car exp))
; not the real deconstructor, but very useful
(define (degroup-repeated exp)
(if (group? exp)
(degroup-repeated (degroup exp))
exp))
; We're gonna be doing this, a lot
; turns a list such as (1 (2 * 4) 3) into (1 + (2 * 4) + 3)
(define (splice-op arglist op)
(cond ((null? arglist) nil) ; 0 args
((null? (cdr arglist)) arglist) ; 1 arg
(else (cons (car arglist)
(cons op
(splice-op (cdr arglist) op))))))
; This does the opposite, assumes op is the top-op of the expression
; eg. (1 + 2 * 4 + 3) => (1 (2 * 4) 3)
(define (extract-op exp op)
(cond ((null? exp) nil)
((null? (cdr exp)) exp)
((null? (cddr exp)) (error "Extract-op from two-member list" exp))
((not (memq (cadr exp) op-order)) (error "Extract-op, second element not an op" exp))
((eq? (cadr exp) op) (cons (car exp)
(extract-op (cddr exp) op)))
(else (cons (grab-subexp exp op)
(extract-op (drop-subexp exp op))))))
; two helper functions for extract-op, extract a beginning subexpression, which uses a
; higher precedence op
; e.g. exp. (2 * 4 + 3 + 5), op: +
; (grab-subexp exp op) => (2 * 4)
; (drop-subexp exp op) => (3 + 5)
;
; exp. (2 * 4 + 3), op: +
; (grab-subexp exp op) => (2 * 4)
; (drop-subexp exp op) => (3)
;
; exp. (2 * 4), op: +
; (grab-subexp exp op) => (2 * 4)
; (drop-subexp exp op) => ()
(define (grab-subexp exp op)
(if (or (null? exp) (eq? op (car exp)))
nil
; if we reach the end of the list, or the top-level op, we stop adding elements
(cons (car exp)
(grab-subexp (cdr exp) op))))
(define (drop-subexp exp op)
(let ((list-from-op (memq op exp)))
(if (not list-from-op)
nil
(cdr list-from-op))))
; accepts a complex expression containing at least one operations
; removes parentheses around subexpressions which use an operator with higher
; precedence
(define (remove-parens list op)
(cond ((null? list) nil)
((or (number? (car list))
(variable? (car list))
; we don't want to remove parentheses around ops of the same precedence
; since we did that while extracting argument lists. And if our operation
; is not associative (e.g. **) this could cause an error
(lower-or-eq-op (top-op (car list)) op))
(cons (car list) (remove-parens (cdr list) op)))
; in any other case, it's either a grouping, or a higher-precedence op
; and we can get rid of the parens
(else (append (car list) (remove-parens (cdr list) op)))))
(define (variable? x) (symbol? x))
(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))
(define (=number? exp num) (and (number? exp) (= exp num)))
(define (not-number? x) (not (number? x)))
(define (filter predicate sequence)
(cond ((null? sequence) nil)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
; instead of the "fold" function in the previous exercise, here we have several
; "optimize" functions for arglists
(define (optimize-+ args)
(let* ((consts (filter number? args))
(rest (filter not-number? args))
(folded-const (apply + consts)))
(if (= folded-const 0)
rest
(append (list folded-const) rest))))
(define (optimize-* args)
(let* ((consts (filter number? args))
(rest (filter not-number? args))
(folded-const (apply * consts)))
(cond ((= folded-const 1) rest)
((= folded-const 0) '(0))
(else (append (list folded-const) rest)))))
(define (optimize-** args)
(cond ((null? args) (error "Empty arg list for ** in optimize-**"))
((null? (cdr args)) args)
(else
(let* ((new-args (cons (car args) ; if len(args)>=2, we first try to
; compute the right hand side recursively
; if afterwards len(args)==2, we try that too
(optimize-** (cdr args))))
(len=2 (null? (cddr new-args)))
(fst (car new-args))
(snd (cadr new-args)))
(cond ((and len=2 (number? fst) (number? snd)) ; both constant
(list (expt (car new-args) (cadr new-args))))
((and len=2 (=number? snd 1))
(list fst))
(else new-args))))))
(define (make-op op x1 x2)
(let* ((ux1 (degroup-repeated x1)) ; now we know our args are either simple nums/vars or
(ux2 (degroup-repeated x2)) ; they're an operation (+,*,**)
(exp->arglist
(lambda (exp) ; as long as our subexpression: exp. is not an operation of the exact
; same type as the one we're creating, the list of extracted args
; should just look like (exp). Otherwise, we need to extract the
; operators from the list
; e.g. op=+, x1 = (2 + 3 + 2 * 4) -> result=(2 3 (2 * 4))
; x2 = (2 * 4) -> result=((2 * 4))
; then we simply append the lists
(if (or (variable? exp)
(number? exp)
(not (eq? op (top-op exp))))
(list exp)
(extract-op exp op))))
(arglist1 (if (and (eq? op '**) ; if both the op we're making, and the left-hand side
(exponentiation? ux1)) ; are an exponentiation, we need to simply
(list ux1) ; parenthesise the left-hand side, don't extract args,
(exp->arglist ux1))) ; because ** is right-associative
(arglist2 (exp->arglist ux2))
(args (append arglist1 arglist2))
(opt-args (cond ((eq? op '+) (optimize-+ args))
((eq? op '*) (optimize-* args))
((eq? op '**) (optimize-** args)))))
; keep in mind, after this step ** must have at least 1 argument,
; +,* can have 0
(cond ((and (eq? op '+) (= (length opt-args) 0)) 0)
((and (eq? op '*) (= (length opt-args) 0)) 1)
((= (length opt-args) 1) (car opt-args))
(else (remove-parens (splice-op opt-args op) op)))))
(define (make-sum a1 a2)
(make-op '+ a1 a2))
(define (make-product m1 m2)
(make-op '* m1 m2))
(define (sum? x) (and (pair? x) (eq? (top-op x) '+)))
; when we split the list using grab/drop-subexp, we might get a list of length
; 1 on either end
(define (addend s) (degroup-repeated (grab-subexp s '+)))
(define (augend s) (degroup-repeated (drop-subexp s '+)))
(define (product? x) (and (pair? x) (eq? (top-op x) '*)))
(define (multiplier p) (degroup-repeated (grab-subexp p '*)))
(define (multiplicand p) (degroup-repeated (drop-subexp p '*)))
; for the purposes of our exponentiation exercise, we need to determine whether
; the exponent is constant so that we can apply the rule correctly
(define (constant? x var)
(or (number? x)
(and (variable? x) (not (same-variable? x var)))
(and (sum? x)
(constant? (addend x) var)
(constant? (augend x) var))
(and (product? x)
(constant? (multiplier x) var)
(constant? (multiplicand x) var))
(and (exponentiation? x)
(constant? (base x) var)
(constant? (exponent x) var))))
(define (make-exponentiation b e)
(make-op '** b e))
(define (exponentiation? x) (and (pair? x) (eq? (top-op x) '**)))
(define (base e) (car e))
(define (exponent e) (caddr e))
(define (deriv exp var)
(cond ((number? exp) 0)
((variable? exp) (if (same-variable? exp var) 1 0))
((sum? exp) (make-sum (deriv (addend exp) var)
(deriv (augend exp) var)))
((product? exp)
(make-sum
(make-product (multiplier exp)
(deriv (multiplicand exp) var))
(make-product (deriv (multiplier exp) var)
(multiplicand exp))))
((exponentiation? exp)
(if (constant? (exponent exp) var)
(make-product (make-product (exponent exp)
(make-exponentiation (base exp)
(make-sum
(exponent exp)
-1)))
(deriv (base exp) var))
(error "non-constant exponents not yet supported: DERIV" exp)))
(else
(error "unknown expression type: DERIV" exp))))

View file

@ -1,15 +0,0 @@
#lang sicp
(define (element-of-set? x set)
(cond ((null? set) false)
((equal? x (car set)) true)
(else (element-of-set? x (cdr set)))))
; we will simply adjoin elements of set1 to set2 if they are not there
; and drop them if they are there
(define (union-set set1 set2)
(cond ((null? set1) set2)
((null? set2) set1)
((element-of-set? (car set1) set2)
(union-set (cdr set1) set2))
(else (union-set (cdr set1) (cons (car set1) set2)))))

View file

@ -1,24 +0,0 @@
#lang sicp
; element-of-set? is the exact same
; O(n)
(define (element-of-set? x set)
(cond ((null? set) false)
((equal? x (car set)) true)
(else (element-of-set? x (cdr set)))))
; O(1)
(define (adjoin-set x set)
(cons x set)) ; we don't have to check anymore
; O(n), where n is the length of set1
(define (union-set set1 set2)
(append set1 set2))
; intersection-set can still be the exact same
; O(n^2)
(define (intersection-set set1 set2)
(cond ((or (null? set1) (null? set2)) '())
((element-of-set? (car set1) set2)
(cons (car set1) (intersection-set (cdr set1) set2)))
(else (intersection-set (cdr set1) set2))))

View file

@ -1,7 +0,0 @@
#lang sicp
(define (adjoin-set x set)
(cond ((null? set) (list x))
((< x (car set)) (cons x set))
((= x (car set)) set)
((> x (car set)) (cons (car set) (adjoin-set x (cdr set))))))

View file

@ -1,11 +0,0 @@
#lang sicp
(define (union-set set1 set2)
(cond ((null? set1) set2)
((null? set2) set1)
((< (car set1) (car set2)) (cons (car set1)
(union-set (cdr set1) set2)))
((= (car set1) (car set2)) (cons (car set1)
(union-set (cdr set1) (cdr set2))))
((> (car set1) (car set2)) (cons (car set2)
(union-set set1 (cdr set2))))))

View file

@ -1,16 +0,0 @@
a)
From my understanding, yes, the lists produced are always going to be equal?
given the same tree
b)
No, they don't, remember than when we `append` two lists, the cons cells for
the first list have to all be reconstructed, which is an additional O(n)
steps, where n is len(first-list).
This means that when we break up a tree in (tree->list-1 tree) T(n) = T(n/2) +
O(n) + T(n/2)
tree->list-2 has one cons operation, which is constant, for each entry, which
means the order of growth is O(n)
On the other hand, tree->list-1 has order of growth: O(n log n)

View file

@ -1,22 +0,0 @@
a)
partial-tree takes a list elts, and n, a number of starting elements which it
will process, it arranges these n elements into a tree and returns a list with
2 elements. The first is a tree of the first n elements, the second is a list
of the remaining elements. The arrangement is done by making a tree out of
(n-1)/2 elements recursively, then adding the one element at the start of the
remainder-list as the current entry, then taking the other half of the n
elements, and recursively arranging them as well.
(list->tree '(1 3 5 7 9 11))
==
5
/ \
1 9
\ / \
3 7 11
b)
Since only the top-level list has its length calculated O(n), while all the
lower ones have theirs calculated in constant time. And in general, every
specific call of partial-tree has a number of constant operations, the total
would be O(n)

View file

@ -1,101 +0,0 @@
#lang sicp
; the helper functions:
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
(define (element-of-set? x set)
(cond ((null? set) false)
((= x (entry set)) true)
((< x (entry set))
(element-of-set? x (left-branch set)))
((> x (entry set))
(element-of-set? x (right-branch set)))))
(define (adjoin-set x set)
(cond ((null? set) (make-tree x '() '()))
((= x (entry set)) set)
((< x (entry set))
(make-tree (entry set)
(adjoin-set x (left-branch set))
(right-branch set)))
((> x (entry set))
(make-tree (entry set) (left-branch set)
(adjoin-set x (right-branch set))))))
(define (tree->list-2 tree)
(define (copy-to-list tree result-list)
(if (null? tree)
result-list
(copy-to-list (left-branch tree)
(cons (entry tree)
(copy-to-list
(right-branch tree)
result-list)))))
(copy-to-list tree '()))
(define tree->list tree->list-2)
(define (list->tree elements)
(car (partial-tree elements (length elements))))
(define (partial-tree elts n)
(if (= n 0)
(cons '() elts)
(let ((left-size (quotient (- n 1) 2)))
(let ((left-result
(partial-tree elts left-size)))
(let ((left-tree (car left-result))
(non-left-elts (cdr left-result))
(right-size (- n (+ left-size 1))))
(let ((this-entry (car non-left-elts))
(right-result
(partial-tree
(cdr non-left-elts)
right-size)))
(let ((right-tree (car right-result))
(remaining-elts
(cdr right-result)))
(cons (make-tree this-entry
left-tree
right-tree)
remaining-elts))))))))
; the exercise itself
(define (union-olist set1 set2)
(cond ((null? set1) set2)
((null? set2) set1)
((< (car set1) (car set2)) (cons (car set1)
(union-olist (cdr set1) set2)))
((= (car set1) (car set2)) (cons (car set1)
(union-olist (cdr set1) (cdr set2))))
((> (car set1) (car set2)) (cons (car set2)
(union-olist set1 (cdr set2))))))
(define (intersection-olist set1 set2)
(if (or (null? set1) (null? set2))
'()
(let ((x1 (car set1)) (x2 (car set2)))
(cond ((= x1 x2)
(cons x1 (intersection-olist (cdr set1)
(cdr set2))))
((< x1 x2)
(intersection-olist (cdr set1) set2))
((< x2 x1)
(intersection-olist set1 (cdr set2)))))))
(define (union-set set1 set2)
(list->tree
(union-olist (tree->list set1)
(tree->list set2))))
(define (intersection-set set1 set2)
(list->tree
(intersection-olist (tree->list set1)
(tree->list set2))))

View file

@ -1,19 +0,0 @@
#lang sicp
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
(define (key record)
(car record))
(define (lookup given-key set-of-records)
(cond ((null? set-of-records) false)
((= given-key (key (entry set-of-records)))
(entry set-of-records))
((< given-key (key (entry set-of-records)))
(lookup given-key (left-branch set-of-records)))
((> given-key (key (entry set-of-records)))
(lookup given-key (right-branch set-of-records)))))

Some files were not shown because too many files have changed in this diff Show more