;;Exercise 2.67
> (decode sample-message sample-tree)
(A D A B B C A)
;;Exercise 2.68
The encode-symbol
procedure I wrote is straightforward, but takes a rather large number of steps to encode a symbol, because we have to search the set of symbols at each node for the correct branch to take. I’m not sure if there’s a better way to do this…
(define (encode-symbol symbol tree)
(cond ((leaf? tree) '())
((element-of-set? symbol (symbols (left-branch tree)))
(cons 0 (encode-symbol symbol (left-branch tree))))
((element-of-set? symbol (symbols (right-branch tree)))
(cons 1 (encode-symbol symbol (right-branch tree))))
(else (error "symbol not in tree - ENCODE-SYMBOL" symbol))))
;;Exercise 2.69
Successive-merge
was actually fairly straightforward to code, however, when I first attempted to do this, I did not fully understand the actual tree generation procedure! Perhaps this is what the authors were warning about when they said it was tricky, I was certainly tricked initially :D
(define (successive-merge leaf-set)
(if (= (length leaf-set) 1)
(car leaf-set)
(successive-merge
(adjoin-set (make-code-tree (car leaf-set)
(cadr leaf-set))
(cddr leaf-set)))))
;;Exercise 2.70
I never knew 50s rock was so repetitive ;)
Probably better than the junk that gets put out these days though…
(define freq-pairs (list (list 'A 2) (list 'BOOM 1) (list 'GET 2) (list 'JOB 2) (list 'NA 16) (list 'SHA 3) (list 'YIP 9) (list 'WAH 1)))
(define message '(GET A JOB
SHA NA NA NA NA NA NA NA NA
GET A JOB
SHA NA NA NA NA NA NA NA NA
WAH YIP YIP YIP YIP YIP YIP YIP YIP YIP
SHA BOOM))
(define rock50s-tree (generate-huffman-tree freq-pairs))
(define encoded-message (encode message rock50s-tree))
(define huffman-length (length encoded-message))
(define logbase2-of-8 3)
(define fixed-length (* (length message) logbase2-of-8))
fixed-length
turns out to be 108 bits long, whereas the huffman-length
is only 84 bits long. That’s a pretty fair length saving.
;;Exercise 2.71
I’m not really a fan of drawing large trees, so I’ll just give the code to generate it.
(define freq-pairs-5 (list (list '1 1) (list '2 2) (list '3 4) (list '4 8) (list '5 16)))
(define freq-pairs-tree-5 (generate-huffman-tree freq-pairs-5))
(define freq-pairs-10 (list (list '1 1) (list '2 2) (list '3 4) (list '4 8) (list '5 16) (list '6 32) (list '7 64) (list '8 128) (list '9 256) (list '10 512)))
(define freq-pairs-tree-10 (generate-huffman-tree freq-pairs-10))
The number of bits required for n=5 code are
Largest frequency: 1
Lowest frequency: 4
For n=10
Largest frequency: 1
Lowest frequency 9
It’s fairly obvious that the largest frequency will always have 1 bit, and the lowest frequency will have (n-1) bits.
;;Exercise 2.72
As we descend the tree we have to search the list of symbols at the node we are on, which is of the order O(n). We will need to descend n levels worst case, therefore n searches n deep is O(n^{2})
;;Exercise 2.59
Implementing union-set is fairly straightforward for the unordered-list representation.
(define (union-set set1 set2)
(cond ((null? set1) set2)
((null? set2) set1)
((element-of-set? (car set1) set2)
(union-set (cdr set1) set2))
(else (cons (car set1) (union-set (cdr set1) set2)))))
;;Exercise 2.60
This exercise was pretty interesting, it makes you think about situations in which what would seem to be an inefficient algorithm is actually the best for a job. Here’s my implementation of the set operations for an unordered set which allows duplicates.
(define (element-of-set? x set)
(cond ((null? set) false)
((equal? x (car set)) true)
(else (element-of-set? x (cdr set)))))
(define (adjoin-set x set)
(cons x set))
(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))))
(define (union-set set1 set2)
(append set2 set1))
From the code we can see that, when duplicates are allowed,
element-of-set?
is still O(n)adjoin-set
is O(1) from O(n)intersection-set
is still O(n^2)union-set
is O(n) from O(n^2)By allowing duplicates, we have sped things up quite a bit, even if the algorithms are going to use up a lot more memory. In choosing which algorithm to use in a certain situation, we need to take into account the environment it will be used in. If we are, for example, on a machine with limited CPU speed, but a lot of memory (not uncommon in machines that have been upgraded), the duplicate representation would be best. On the other hand, if we were dealing with huge numbers, it would be a big drain on memory to use the duplicate representation, and the non-duplicate representation would be better for keeping overhead down.
;;Exercise 2.61
Now we’re starting to optimize the representations a bit more, it’s really neat to see how simple ideas like ordering the sets can produce fairly large performance gains :)
(define (adjoin-set x S)
(cond ((null? S) (list x))
((< x (car S)) (cons x S))
((> x (car S)) (cons (car S) (adjoin-set x (cdr S))))
((= x (car S)) S)))
The ordered-list representation will take less time to adjoin, on the average, because we will not necessarily have to process the whole list in order to know if a duplicate exists.
;;Exercise 2.62
This particular exercise required a fair bit of thought. Here’s my explanation.
If the first element of set1 is less than the first element of set2, we make that element the car of a new list, and the cdr of the new list is the union of the cdr of set1 and set2…
(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 set2) (union-set set1 (cdr set2))))
((= (car set1) (car set2))
(cons (car set1)
(union-set (cdr set1)
(cdr set2))))))
;;Exercise 2.63
;;A
I think this exercise is designed to see how well we can transform a diagram into the actual representation of a tree as the most difficult part was writing down the trees :D
(define tree1 (make-tree 7
(make-tree 3
(make-tree 1 '() '())
(make-tree 5 '() '()))
(make-tree 9
'()
(make-tree 11 '() '()))))
(define tree2 (make-tree 3
(make-tree 1 '() '())
(make-tree 7
(make-tree 5 '() '())
(make-tree 9
'()
(make-tree 11 '() '())))))
(define tree3 (make-tree 5
(make-tree 3
'()
(make-tree 1 '() '()))
(make-tree 9
(make-tree 7 '() '())
(make-tree 11 '() '()))))
After running these through both functions, you’ll see that both the recursive and iterative procedures produce the same result, which is expected if they are to do the same job…
;B
Yes, they both have the same order of growth, however tree->list-2 uses less memory than tree->list-3, and thus could be faster in certain situations.
;;Exercise 2.64
Partial-tree
works in a very recursive fashion :)
The best way I can explain is to work through an example.
Let’s say we have the list '(1 2 3 4 5)
to turn into a tree.
Partial-tree
first assigns equal, or almost equal sizes for the left and right branch of the new tree. So for our tree left-size
will be 2, and right-size
will be 3 (because the size of the list is not even). Then, partial tree
cons
es together the result of partial-tree
on the left and right halves of the given list. It’s quite a bit for me to wrap my head around, to be sure!
;;Exercise 2.65
Still a work in progress for me…
;;Exercise 2.66
The lookup
procedure is basically element-of-set?
, except instead of returning true or false, we return the item requested by key, or false if it’s not found.
(define (lookup key records)
(cond ((null? records) false)
((= key (entry records)) (record-value (entry records)))
((< key (entry records))
(lookup key (left-branch records)))
((> key (entry records))
(lookup key (right-branch records)))))
;;Where a record structure looks like
(define (make-record key value)
(cons key value))
]]>I spent my entire day today working on this awesome song, which I’ve titled “Walk Through The Desert”. It’s a sort of rock balladish thing, and I’m quite pleased with what I managed to knock out in ten hours. Yesterday I randomly decided to listen to some “Ramble On Rose” by The Grateful Dead, and jammed along with it for a little while. I got an interesting chord progression out of that jam, and I was in a bit of an interesting mood, so I sung along to the riff and came up with some random lyrics for it. Today I decided to flesh it out a bit, so I got the guitar out, plugged along and came up with some lyrics that actually made sense. Because I’m not wonderful at keeping time, I made up a little drum beat using Hydrogen. To record my guitar playing, I used a rather old webcam microphone wrapped in a (clean) sock. This produced surprisingly good results!
I then spent a good few hours coming up with an interesting guitar accompaniment, which I am very pleased with. When I developed this accompaniment, I basically had an idea of what it would sound like in my head, but I didn’t bother to figure out what scale (if any ;) it was actually in. I find that this approach actually lets me experiment more, as I’m not constrainedÂ by what I “should” be playing. While I was figuring out my guitar part, I made sure to record all of what I was doing, using chord charts, and tabulation. I used audacity for all my recording, and it took plenty of takes for me to actually hit it right, so it was good to have a good method of recording in pieces.
It snowballed from there, and after spending a good few hours coming up with some guitar accompaniment, I can now present to the general public, “Walk Through The Desert”.
Before I forget, I also need to note the command that I used to turn it into a video
ffmpeg -ab 192k -i logo.jpg -i walk_through_the_desert.mp3 desert.avi
-ab is the bitrate I want the music to be, which I’ve set to 192k, a fairly typical rate
-i logo.jpg specifies the image to use as the background (I’m pretty sure it needs to be jpeg)
-i walk_through_the_desert.mp3 is the mp3 file to use as audio backing.
Also, for those who are interested, here’s my studio :)
]]>It’s been a while. I purchased an electric guitar about two months ago, and from the moment it arrived, I’ve been pretty much playing guitar in my free time. So yes, not much work has been done on SICP in that interval, but I’ve certainly learned a lot about guitar in that time.
Reasons
It seems a bit spontaneous, to me, to decide to pick up guitar, but I’ve had this ache since I got into listening to rock music (~age thirteen) to learn to play guitar. Of course, when I was thirteen I lacked two things. The perseverance to actually keep going with it no matter the boredom, pain, and whatnot, and also the money to actually buy the equipment I needed. That ache has been on the backburner for a while (read 3 years :), but recently, when I began to listen to some really great guitar it was reawakened. Hearing Joe Satriani smash out a solo, or just some meaty power chords from deep purple made me wish I could experience that. So when I decided to get a guitar a couple months ago, I had a clear goal in mind. I knew that I wouldn’t be JS in a month, but what I could do, was have fun! I decided for both cost purposes and the interest of fun to forgo getting professional lessons. I believe this is the right approach, at least for me, because I’m not burdened by the boredom of running through the same exercise fifty times ’til my fingers seize up; I can just grab a tab or two and practise.
The Equipment
It was also in the interest of “fun” that I decided to purchase a Squier Stratocaster electric. There’s just so much more you can do with an electric, and after hearing a lot of my friends recommend it as a good beginners guitar I was set. It was also cheap, only ~$150. I also needed an amp, and after a fair amount of research I decided to get an orange crush 10. Orange make beautiful amps, and my ~$200 solid state amp is testament to that. Of course, the best way to save money is to use eBay, so I bought my gear from there, saved about $50, including postage, of course.
…
So, yes, I’ve managed to learn quite a bit in the last two months, and I’ve had a heck of a lot of fun doing it! Guitar is a really great instrument to play; it’s very expressive. It’s quite easy to bend strings, add a bit of tremolo, and you can apply numerous effects to modify your sound. I personally have also got an MXR Carbon Copy delay pedal, for stretching out rhythm pieces, and giving a bit of sustain to reggae sounds.
I’ll leave you with that, my next post will feature a song I’ve composed, and the method I used to record it.
Happy Hacking!
]]>Anyway, here’s a short sequence of images to demonstrate the method:
]]>Changes:
It’s been a very educational experience working with ncurses and C, which are both very new to me, but I’m getting better at interpreting gcc’s error messages… often 10 lines of error can be generated by something as simple as a missed closing bracket! I also finally got around to writing a makefile for the project, which simplifies the task of building it quite a lot. make debug
is all I need to get debuggable code ready.
That’s all for now, I plan to post something on the actual game mechanics sometime soon, as always, you can enjoy the game by grabbing it from github
]]>I’m still working through SICP, I’m working on the part about data structures for sets.
I have done a total rewrite of my NCurses PONG Clone, and present to you the result:
I’ve got AI, a scoreboard and a few other things which I’m currently working on, check out the code at github
]]>What’s New
The transform editor was written using tkinter, and so for that reason it is neither pretty nor quick (for some reason tkinter does not support drawing directly to a canvas, you have to make objects on the canvas), but it does the job well, and I’ve managed to create quite a few neat looking fractals with it. In the future I hope to make a gtk or qt interface, but until then, it should do the job.
I’ll need to tidy up and standardize the command line arguments to pyafg, because I’ve added a lot more options. Here is an example of gradient coloring.
Here is a shot of the gradient for the above image.
]]>;;Exercise 2.53
As usual, just a check to make sure we understand how to manipulate symbolic data.
>(list '(a b c))
(a b c)
>(list (list 'george))
((george))
>(cdr '((x1 x2) (y1 y2)))
(y1 y2)
>(cadr '((x1 x2) (y1 y2)))
y1
>(pair? (car '(a short list)))
#f
>(memq 'red '((red shoes) (blue socks)))
#f
>(memq 'red '(red shoes blue socks))
(red shoes blue socks)
;;Exercise 2.54
A fairly straightforward implementation of the recursive description they gave.
(define (my-equal? a b)
(cond ((and (eq? a '()) (eq? b '())) true)
((and (symbol? a) (symbol? b))
(eq? a b))
((and (pair? a) (pair? b))
(and (my-equal? (car a) (car b))
(my-equal? (cdr a) (cdr b))))
(else false)))
;;Exercise 2.55
The first challenging question. Had me stumped for a while, even when I typed the code in at my interpreter I didn’t get it, however, if you notice the footnote no. 34, it explains that the interpreter replaces each use of '
with a quote
. So ''abracadabra
is '(quote abracadabra)
, and the car of that list is the symbol quote
!
;;Exercise 2.56
We’ve been introduced to the differentiation program, a very nice example of abstraction. The key to this exercise is pretty much to copy what happens for the other rules, just supplying different selectors and constructors, and a bit more code in the deriv function. I’m a bit of a rebel ;) I chose to use the ‘^ symbol instead of ‘**, as ‘^ seems more intuitive to me :)
Here are the selectors, predicate, and constructors:
;;'(^ b a)
(define (exponentiation? x)
(and (pair? x) (eq? (car x) '^)))
(define (base x)
(cadr x))
(define (exponent x)
(caddr x))
(define (make-exponentiation base exponent)
(cond ((and (number? base) (number? exponent))
(expt base exponent))
((=number? exponent 0) 1)
((=number? exponent 1) base)
(else (list '^ base exponent))))
And here is the modified deriv function:
(define (deriv expr var)
(cond ((number? expr) 0)
((variable? expr)
(if (same-variable? expr var) 1 0))
((exponentiation? expr) ;;EXPONENTIATION RULE
(make-product
(make-product (exponent expr)
(make-exponentiation (base expr)
(- (exponent expr) 1)))
(deriv (base expr) var)))
((sum? expr)
(make-sum (deriv (addend expr) var)
(deriv (augend expr) var)))
((product? expr)
(make-sum
(make-product (multiplier expr)
(deriv (multiplicand expr) var))
(make-product (deriv (multiplier expr) var)
(multiplicand expr))))
(else
(error "unknown expression type -- DERIV" expr))))
And a test,
>(deriv '(^ x 4) 'x)
(* 4 (^ x 3))
;;Exercise 2.57
I had some initial difficulties with this question, I understood what I was attempting to do in the selectors, but the constructors were a little trickier. With the selectors, the only interesting bit is in the augend selector. When we get the augend, we must remember if there is a list, we need to return it as the sum of the rest of the items in the list, not a a list of two or more numbers. eg. (augend ‘(+ 1 2 3)) is (+ 2 3) not (2 3).
(define (addend s) (cadr s))
(define (augend s)
(let ((aug (cddr s)))
(if (eq? (cdr aug) '())
(car aug)
(make-sum (car aug)
(cdr aug)))))
The constructor also held me up for a little while, as I had a bit of a hiccup in my code.
I was not combining the augend a2 into the list (‘+ a1 a2) correctly. This is best shown with some code…
>(make-sum x (2 (* 5 y)))
(+ x (2 (* 5 y)))
As you can see, instead of combining the 2 at the same level as x, it is a separate list, (2 (* 5 y)) which the program does not know how to parse. It should of course be (+ x 2 (* 5 y)). How do we combine the lists? Using append! Here is the constructor then:
(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (append (list '+ a1) a2))))
Note that we can leave all the simplification code in, it will still work even in the new format. The changes to product are almost exactly the same as the changes to sum, I feel as though there’s an underlying abstraction somewhere ;)
Here’s the full code, including the product as well as sum, remember that this is all available on my sicp github repo.
;;(+ x y z)
(define (addend s) (cadr s))
(define (augend s)
(let ((aug (cddr s)))
(if (eq? (cdr aug) '())
(car aug)
(make-sum (car aug)
(cdr aug)))))
(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (append (list '+ a1) a2))))
;;'(* x y z)
(define (multiplier p) (cadr p))
(define (multiplicand p)
(let ((mult (cddr p)))
(if (eq? (cdr mult) '())
(car mult)
(make-product (car mult)
(cdr mult)))))
(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 (append (list '* m1) m2))))
;;Exercise 2.58
;;Part A
Things are getting interesting, we are now getting out of the safe world of polish notation, and into the rather complex one of parsing infix expressions. However, part a is very easy to implement, it simply requires swapping the parsing of the operator and the first operand, the change is exactly the same for multiplication.
(define (sum? x)
(and (pair? x) (eq? (cadr x) '+)))
(define (addend s) (car s))
(define (augend s) (caddr s))
(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))))
;;Part B
Part b is simply put, a beast of a question. It most certainly is quite a difficult problem, but it’s definitely possible! In fact, I suggest you stop reading now, so that you can have the same exhiliration that I got upon solving it! We are now required to parse infix expressions with any or no parenthization. I mulled over this one for a couple days, and spent more than a few nights writing attempts to solve it in my note book. I finally hit epiphany at badminton on Thursday (6/5/10) night.
Before we do anything, we should state what we are attempting to accomplish with our code. This is a bit trickier than it sounds, so let’s go through a couple examples and see if we can find anything interesting.
(x * (6 + y) + 5)
is equivalent to
((x * (6 + y)) + 5)
(note the extra parenthesis before x)
So one thing we need to do is replace parentheses to make it easier to parse.
(x * (6 + y) + 5)
can be reduced like so:
addend: x * (6 + y)
multiplier: x
multiplicand: (6 + y)
addend: 6
augend: y
augend:
This looks like a job for recursion to me, and it also looks like we’ll need to worry about putting sums in the right place before the products. For example, if we tried to grab the multiplicand of (3 * 6 + 5) we would obtain 6 + 5 instead of 6.
We can come up with a simple recursive definition for this:
If the augend of expr is a sum, then the augend of expr is the sum of everything after the sum operator in expr (y + 3* z). If the augend of expr is a product, then the augend of expr is the product of everything after the product operator in expr. If the augend of expr is a single variable then the augend of expr is the first item after the sum operator. Finally if the augend of expr is a single number, then the augend of expr is the first item after the sum operator.
So we can see that there are four rules to apply here which will eventually filter down to the base case of the single variable or number. So, the first thing we will implement is the definition of a sum and product. An expression is a sum if it has the ‘+ operator in it, and an expression is a product if it has only the ‘* operator in it. This gives us the proper operator precedence. The in? predicate here tells whether a given symbol is in a list.
(define (sum? x)
(and (pair? x) (in? '+ x)))
(define (product? x)
(and (pair? x) (not (in? '+ x)) (in? '* x)))
Now that we have our definitions of what constitutes a sum, we need to give the definitions of addend and augend. The addend is everything before the first ‘+ operator, but we also need to process the addend (remember the recursive definition) to correctly resolve operator precedence in it. We will do this with the recursive process stated above as a procedure named process-expr which I will leave unspecified. Remember that black box abstraction, and wishful thinking are very important. Anyway, here’s the definition of addend and augend, split-on is a function which gives a cons where the car is everything before the symbol, and the cdr is everything after the symbol.
>(split-on '+ (1* x + 2 * y))
((1 * x) 2 y)
(define (addend s)
(process-expr (car (split-on '+ s))))
(define (augend s)
(process-expr (cdr (split-on '+ s))))
Now it’s almost all in place, there’s one more definition left, how do we construct a sum? This is very easy, and stays the same as what we implemented for part A, (list a1 '+ a2).
Now, to implement the process-expr procedure. Since we have already defined all the selectors and constructors, this will be very easy.
(define (process-expr expr)
(cond ((if (= (length expr) 1) (variable? (car expr)) false) (car expr))
((if (= (length expr) 1) (number? (car expr)) false) (car expr))
((sum? expr) (make-sum (addend expr)
(augend expr)))
((product? expr) (make-product (multiplier expr)
(multiplicand expr))))))
This is a beautiful example of mutual recursion, and the great thing is, that it works! I first wrote this while waiting to play at badminton, and when I tranferred it from paper, it worked first try, with just a couple hiccups. One of those hiccups was the parsing of a parenthized expression such as (3 * (5 + 4))
. The augend of this expression is ((5 + 4)), which is (list (list 5 + 4)). When process-expr encounters this, it checks if it is a variable, but while the length of (list (list 5 ‘+ 4)) is 1, it will not satisfy either the variable? or the number? predicate. It will then check if it is a sum, but there is no ‘+ in (list (list 5 + 4)), and it will also check if it is a product, but it won’t satisfy that either, so the cond expression will return #void! This is a bit of a bug, but it is fairly easy to fix. Let’s think of a parenthized-expression as another type of expression. It must satisfy these requirements to be considered parethized:
This is readily expressed as a procedure.
(define (parenthized-expression? expr)
(and (not (variable? expr))
(not (number? expr))
(= (length expr) 1)
(or (sum? (car expr))
(product? (car expr)))))
;;Selector
(define (deparenthize expr) (car expr))
Now, we just need to add a rule for handling parenthized-expressions to process-expr. This is accomplished by adding a let expression, which will bind expr correctly:
(define (process-expr expr)
(let ((expr (if (parenthized-expression? expr) (deparenthize expr) expr)))
(cond ((if (= (length expr) 1) (variable? (car expr)) false) (car expr))
((if (= (length expr) 1) (number? (car expr)) false) (car expr))
((sum? expr) (make-sum (addend expr)
(augend expr)))
((product? expr) (make-product (multiplier expr)
(multiplicand expr))))))
We’re done! We have now created a fairly useful symbolic differentiator, which can handle (almost) arbitrary expressions. There is nothing as exhilirating as solving a really tough problem, and this can definitely be ranked as one of them! Here is all the code, and remember, this code is on my sicp github repo.
Happy Hacking!
;;Split an expr on symb
(define (split-on symb expr)
(define (iter r l)
(cond ((eq? l '()) r)
((eq? symb (car l)) (cons r (cdr l)))
(else (iter (append r (list (car l))) (cdr l)))))
(iter '() expr))
;;Is symb in expr?
(define (in? symb expr)
(cond ((eq? expr '()) false)
((eq? symb (car expr)) true)
(else (in? symb (cdr expr)))))
;; representing algebraic expressions
(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)))
;;Is expr a parenthized expression? eg. ((1 + 2))
(define (parenthized-expression? expr)
(and (not (variable? expr))
(not (number? expr))
(= (length expr) 1)
(or (sum? (car expr))
(product? (car expr)))))
(define (process-expr expr)
(let ((expr (if (parenthized-expression? expr) (deparenthize expr) expr)))
(cond ((if (= (length expr) 1) (variable? (car expr)) false) (car expr))
((if (= (length expr) 1) (number? (car expr)) false) (car expr))
((sum? expr) (make-sum (addend expr)
(augend expr)))
((product? expr) (make-product (multiplier expr)
(multiplicand expr))))))
(define (deparenthize expr) (car expr))
;;'(+ x y)
(define (sum? x)
(and (pair? x) (in? '+ x)))
(define (addend s)
(process-expr (car (split-on '+ s))))
(define (augend s)
(process-expr (cdr (split-on '+ s))))
(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))))
;;'(* x y)
(define (product? x)
(and (pair? x) (not (in? '+ x)) (in? '* x)))
(define (multiplier p)
(process-expr (car (split-on '* p))))
(define (multiplicand p)
(process-expr (cdr (split-on '* p))))
(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 (deriv expr var)
(cond ((number? expr) 0)
((variable? expr)
(if (same-variable? expr var) 1 0))
((sum? expr)
(make-sum (deriv (addend expr) var)
(deriv (augend expr) var)))
((product? expr)
(make-sum
(make-product (multiplier expr)
(deriv (multiplicand expr) var))
(make-product (deriv (multiplier expr) var)
(multiplicand expr))))
(else
(error "unknown expression type -- DERIV" expr))))
>(deriv '(x + 3 * (x + y + 2)) 'x)
4