Add exercises from section 2.4
This commit is contained in:
parent
f318ae0a70
commit
b326460d60
4 changed files with 151 additions and 0 deletions
50
chapter-2/ex-2.73.txt
Normal file
50
chapter-2/ex-2.73.txt
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
a) The predicates `number?` and `variable?` can't be assimilated because they
|
||||||
|
are checking the data type of the datum itself, not the value of a specific
|
||||||
|
symbol which can be found in a table.
|
||||||
|
|
||||||
|
b) Here I'll only write the most basic version of the procedures, since the
|
||||||
|
more elaborate versions were done in previous exercises.
|
||||||
|
|
||||||
|
(define (install-deriv-package)
|
||||||
|
(define (deriv-sum operands var)
|
||||||
|
(let ((addend (car operands))
|
||||||
|
(augend (cadr operands)))
|
||||||
|
(make-sum (deriv addend var)
|
||||||
|
(deriv augend var))))
|
||||||
|
|
||||||
|
(define (deriv-product operands var)
|
||||||
|
(let ((multiplicand (car operands))
|
||||||
|
(multiplier (cadr operands)))
|
||||||
|
(make-sum
|
||||||
|
(make-product multiplier
|
||||||
|
(deriv multiplicand var))
|
||||||
|
(make-product (deriv multiplier var)
|
||||||
|
multiplicand))))
|
||||||
|
|
||||||
|
(put 'deriv '+ deriv-sum)
|
||||||
|
(put 'deriv '* deriv-product)
|
||||||
|
'done)
|
||||||
|
|
||||||
|
c) exponential rule:
|
||||||
|
...
|
||||||
|
(define (deriv-expon operands var)
|
||||||
|
(let ((base (car operands))
|
||||||
|
(exponent (cadr operands)))
|
||||||
|
(if (constant? exponent var)
|
||||||
|
(make-product (make-product exponent
|
||||||
|
(make-exponentiation base
|
||||||
|
(make-sum
|
||||||
|
exponent
|
||||||
|
-1)))
|
||||||
|
(deriv base var))
|
||||||
|
(error "non-constant exponents not yet supported: DERIV" exponent))))
|
||||||
|
...
|
||||||
|
(put 'deriv '** deriv-expon)
|
||||||
|
...
|
||||||
|
|
||||||
|
d) if the dispatch line looked like this:
|
||||||
|
((get (operator exp) 'deriv) (operands exp) var)
|
||||||
|
|
||||||
|
the only part we would really have to change is the put lines for each of the
|
||||||
|
functions, like so:
|
||||||
|
(put 'deriv '+ deriv-sum) -> (put '+ 'deriv deriv-sum)
|
59
chapter-2/ex-2.74.txt
Normal file
59
chapter-2/ex-2.74.txt
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
This is a txt file because there's no sense in trying to make it into a proper
|
||||||
|
runnable scheme file, unless I go out of my way to make several examples of
|
||||||
|
data structure and record formats, complete with examples in order to actually
|
||||||
|
run these:
|
||||||
|
|
||||||
|
a) Before any of the data records in the file itself, there should be an
|
||||||
|
identifier for what type of record it is, so each file should start with a
|
||||||
|
symbol, number or string that uniquely identifies the file structure/format,
|
||||||
|
for example:
|
||||||
|
european-division-format
|
||||||
|
(...)
|
||||||
|
(...)
|
||||||
|
...
|
||||||
|
|
||||||
|
This piece of info should be in the same position in every file, so that a
|
||||||
|
uniform function, say (get-file-type file) could be used to find the proper
|
||||||
|
format. If it's not possible to change these division formats at all, then
|
||||||
|
either this change will be done while loading the file, or, the get-file-type
|
||||||
|
function will have to be more complicated.
|
||||||
|
|
||||||
|
In any case, once we have solved the format marking issue using any kind of
|
||||||
|
method, the files and the records could be structured any how, as long as each
|
||||||
|
record has a unique identifier to the employee.
|
||||||
|
|
||||||
|
These can then be searched with different functions for different formats, all
|
||||||
|
of which could be organized in a table, and called by a master function, which
|
||||||
|
will load the record, and then attach it with a tag, which will make record
|
||||||
|
processing easier too:
|
||||||
|
|
||||||
|
(define (get-record name file)
|
||||||
|
(let ((file-type (get-file-type file)))
|
||||||
|
(attach-record-type file-type
|
||||||
|
((get 'get-record file-type) name))))
|
||||||
|
|
||||||
|
We will also assume all these functions return nil if the record doesn't
|
||||||
|
exist, or a single record if it does.
|
||||||
|
|
||||||
|
b) The way that we've written the get-record function, it doesn't matter how a
|
||||||
|
particular employee record is structured, because we tag it as the respective
|
||||||
|
file type ourselves, but of course it must contain the salary field, we must
|
||||||
|
also define a function which gets the record type, and the rest of the record:
|
||||||
|
get-record-type and get-record-body
|
||||||
|
|
||||||
|
(define (get-salary record)
|
||||||
|
((get 'get-salary (get-record-type record)) (get-record-body record)))
|
||||||
|
|
||||||
|
c) We assume there's only one employee for the given name
|
||||||
|
|
||||||
|
(define (find-employee-record name files)
|
||||||
|
(let ((returns (filter (lambda (record) (not (null? record)))
|
||||||
|
(map get-record files))))
|
||||||
|
(if (null? returns)
|
||||||
|
nil
|
||||||
|
(car returns))))
|
||||||
|
|
||||||
|
d) All changes could be done in the new company's (or department's) package,
|
||||||
|
where they would simply define a new format name, add the format name tag to
|
||||||
|
their records, modify their get-record and get-salary functions appropriately,
|
||||||
|
and then add these to the updated global function table.
|
10
chapter-2/ex-2.75.scm
Normal file
10
chapter-2/ex-2.75.scm
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#lang sicp
|
||||||
|
|
||||||
|
(define (make-from-real-imag r a)
|
||||||
|
(define (dispatch op)
|
||||||
|
(cond ((eq? op 'real-part) (* r (cos a)))
|
||||||
|
((eq? op 'imag-part) (* r (sin a)))
|
||||||
|
((eq? op 'magnitude) r)
|
||||||
|
((eq? op 'angle) a)
|
||||||
|
(else (error "Unknown op: MAKE-FROM-MAG-ANG" op))))
|
||||||
|
dispatch)
|
32
chapter-2/ex-2.76.txt
Normal file
32
chapter-2/ex-2.76.txt
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
Explicit dispatch:
|
||||||
|
New type: A new constructor(s), must be made for the new data type, which
|
||||||
|
will add the necessary fields and attach a new type tag. Each of the
|
||||||
|
functions for the type will need to have a new condition line to check for
|
||||||
|
the new type.
|
||||||
|
New op: The new op will be written in an explicit dispatch style to process
|
||||||
|
all of the preexisting types
|
||||||
|
|
||||||
|
Data-directed style:
|
||||||
|
New type: A new package will be written, complete with all the necessary
|
||||||
|
functions to process the new type, they will then all be added to a new
|
||||||
|
row in the table
|
||||||
|
New op: Each existing package will have the op added to it, and will also
|
||||||
|
add it to a new column in the table
|
||||||
|
|
||||||
|
Message-passing style:
|
||||||
|
New type: A new dispatch function will be created, with all of the lines
|
||||||
|
which exist in functions of previous types
|
||||||
|
New op: A new line is added into each of the dispatch functions of the
|
||||||
|
preexisting types
|
||||||
|
|
||||||
|
If new operations are often added, you may prefer the explicit dispatch style,
|
||||||
|
since it involves only creating/modifying one place in the codebase.
|
||||||
|
|
||||||
|
If new types are often added, you may instead prefer one of the other two
|
||||||
|
styles, since here, an addition of a new type is done in one place in the
|
||||||
|
code, while adding a new op requires changes in many places.
|
||||||
|
|
||||||
|
That being said, the data-directed style has the extra advantage that it could
|
||||||
|
(in principle) be written in a way that's more organized for adding new
|
||||||
|
operations, since the table structure itself will work equally well in either
|
||||||
|
case, and it's more of a matter of code organization.
|
Loading…
Add table
Reference in a new issue