Some more progress
This commit is contained in:
parent
493e14692e
commit
9a365b2ed4
12
README.md
12
README.md
@ -1,13 +1,11 @@
|
|||||||
# hello
|
# SICP
|
||||||
|
|
||||||
This repository is where I keep my solutions to the problems in SICP
|
This repository is where I keep my solutions to the problems in SICP.
|
||||||
|
|
||||||
I'm currently working through the book and wanted to keep track of my progress somewhere.
|
I'm currently working through the book and wanted to keep track of my progress somewhere.
|
||||||
Note: I won't be solving ***ALL*** problems. I just solve *most*, I will probably ignore
|
Note: I won't be solving ***ALL*** problems. I just solve *most*, I will probably ignore
|
||||||
those that seem like they would take too long (or ones that require several PhD's to solve).
|
those that seem like they would take too long (or ones that require several PhD's to solve).
|
||||||
|
|
||||||
Note: these are all racket files, I am also learning racket at the same time (and using
|
Note that some of the solutions were done in racket. I started with racket, but eventually
|
||||||
DrRacket) so beware of that. I will mostly try to stick to racket, but there may be
|
I switched to common lisp. Right now I'm using Emacs with SLIME, and will hopefully be
|
||||||
times where I switch to `#lang r5rs` or `#lang sicp` for compatability with the book.
|
continuing with that for the rest of the book.
|
||||||
|
|
||||||
Also, I will put related-seeming or close-together problems in the same file.
|
|
||||||
|
@ -183,6 +183,7 @@
|
|||||||
;; to the table as well.
|
;; to the table as well.
|
||||||
|
|
||||||
;; Note: this problem is sometimes referred to as the "expression problem."
|
;; Note: this problem is sometimes referred to as the "expression problem."
|
||||||
|
;; especially within compiler development.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
60
sec-2-5.lisp
Normal file
60
sec-2-5.lisp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
;; 2.77
|
||||||
|
;; obviously magnitude isn't defined yet on the complex type,
|
||||||
|
;; it is only defined in the internal types, i.e. the secondary types.
|
||||||
|
;; this means that the first apply-generic will immediately fail.
|
||||||
|
;; the reason Alyssa's fix works, is because this makes the
|
||||||
|
;; maginute function dispatch to itself when seing the type
|
||||||
|
;; '(complex). Then, magnitude will be called with the
|
||||||
|
;; internal type - e.g. '(rectangular 3 4), which gives
|
||||||
|
;; the correct answer.
|
||||||
|
|
||||||
|
;; 2.78
|
||||||
|
|
||||||
|
(defun type-tag (datum)
|
||||||
|
(cond
|
||||||
|
((consp datum) (car datum))
|
||||||
|
((numberp datum) 'number)
|
||||||
|
(t (error "unkown type"))))
|
||||||
|
|
||||||
|
(defun contents (datum)
|
||||||
|
(cond
|
||||||
|
((consp datum) (cdr datum))
|
||||||
|
((numberp datum) datum)
|
||||||
|
(t (error "unknown type"))))
|
||||||
|
|
||||||
|
;; assuming the dispatch function actually calls the function with
|
||||||
|
;; the contents of each datum, then you should now be able to just
|
||||||
|
;; insert #'+, #'*, #'- and #'/
|
||||||
|
|
||||||
|
;; 2.79
|
||||||
|
|
||||||
|
;; 2.81
|
||||||
|
;; First, apply-generic is called.
|
||||||
|
;; 'exp is not defined on complex numbers. Therefore, the apply-generic
|
||||||
|
;; function somewhat mistakenly enters the second branch, and first tries
|
||||||
|
;; to find a coercion from the first argument's type to the second argument's
|
||||||
|
;; type. It finds this coercion function. But then it calls:
|
||||||
|
;; (apply-generic op (t1->t2 a1) a2)
|
||||||
|
;; this is a problem, because it now enters an infinite loop. Every time,
|
||||||
|
;; apply-generic will try to find the 'exp method, not find it, and try
|
||||||
|
;; to coerce the first argument to the second argument's type.
|
||||||
|
;; It will succeed, and call itself again.
|
||||||
|
;; Since this is a tail call, it will be optimised and this will be reduced
|
||||||
|
;; to an infinite loop.
|
||||||
|
;;
|
||||||
|
;; Something can be done about it. We can simply compare the tags of
|
||||||
|
;; the objects before trying to coerce - and we can simply raise an error
|
||||||
|
;; if both objects have been coerced to the same type and there is still
|
||||||
|
;; no function found. Coincidentally, this would also prevent Louis Reasouner's
|
||||||
|
;; previous infinite loop.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; In order to be extra spicy, I will be completing the exercises in
|
||||||
|
;; the symbolic algebra section through the use of CLOS.
|
||||||
|
;; I.e. I will actually build an AST of these objects, and use
|
||||||
|
;; methods to parse, interpret and modify them.
|
||||||
|
|
||||||
|
;; Tomorrow. I will do that tomorrow.
|
||||||
|
|
||||||
|
|
134
sec-3-3.scm
Normal file
134
sec-3-3.scm
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
|
||||||
|
;; I am not drawing box-and-pointer diagrams lmao
|
||||||
|
;; still, to answer 3.12:
|
||||||
|
|
||||||
|
;; first:
|
||||||
|
;; (cdr x)
|
||||||
|
;; => '(b)
|
||||||
|
;; because x is not modified in the call to append
|
||||||
|
|
||||||
|
;; however, append! modifies the underlying data structure
|
||||||
|
;; held in x, hence the second (cdr x) returns:
|
||||||
|
;; => '(b c d)
|
||||||
|
|
||||||
|
(define (append! x y)
|
||||||
|
(set-cdr! (last-pair x) y)
|
||||||
|
x)
|
||||||
|
|
||||||
|
(define (last-pair x)
|
||||||
|
(if (null? (cdr x)) x (last-pair (cdr x))))
|
||||||
|
|
||||||
|
;; don't run these twice, you'll create a circular list.
|
||||||
|
;; I lost a good many REPL's to this.
|
||||||
|
(define x '(a b))
|
||||||
|
(define y '(c d))
|
||||||
|
(append! x y)
|
||||||
|
x ; => '(a b c d)
|
||||||
|
(cdr x) ; => '(b c d)
|
||||||
|
|
||||||
|
|
||||||
|
;; 3.13:
|
||||||
|
;; oh! how very nice - a question about the very thing I just
|
||||||
|
;; wrote about.
|
||||||
|
|
||||||
|
;; the REPL hangs. It tries to traverse to the end of a list
|
||||||
|
;; that doesn't have an end. Like most human lives, it dies
|
||||||
|
;; a meaningless death in search of that which does not exist,
|
||||||
|
;; a search that goes round and round and round forever.
|
||||||
|
|
||||||
|
;; I.e. we constructed a cyclical list.
|
||||||
|
|
||||||
|
;; 3.14:
|
||||||
|
;; This is a list reversal procedure.
|
||||||
|
;; The input list is destructively reversed in-place, i.e. with
|
||||||
|
;; no allocations.
|
||||||
|
|
||||||
|
;; v will still refer to the same cons cell, so its value is
|
||||||
|
;; '(a)
|
||||||
|
;; w will refer to the new head of the (now-reversed) list.
|
||||||
|
;; '(d c b a)
|
||||||
|
|
||||||
|
(define (mystery x)
|
||||||
|
(define (loop x y)
|
||||||
|
(if (null? x)
|
||||||
|
y
|
||||||
|
(let ((temp (cdr x)))
|
||||||
|
(set-cdr! x y)
|
||||||
|
(loop temp x))))
|
||||||
|
(loop x '()))
|
||||||
|
|
||||||
|
;; this procedure is useful because its sometimes very convenient
|
||||||
|
;; to generate data into a list through cons cells, then reverse
|
||||||
|
;; it at the end (through an efficient reversal procedure like this)
|
||||||
|
|
||||||
|
;; 3.16:
|
||||||
|
|
||||||
|
(define (count-pairs x)
|
||||||
|
(if (not (pair? x))
|
||||||
|
0
|
||||||
|
(+ (count-pairs (car x))
|
||||||
|
(count-pairs (cdr x))
|
||||||
|
1)))
|
||||||
|
|
||||||
|
(count-pairs '(a b c)) ; => 3
|
||||||
|
|
||||||
|
(define fourbase (cons 1 '()))
|
||||||
|
(define four (cons fourbase (cons fourbase '())))
|
||||||
|
(count-pairs four) ; => 4
|
||||||
|
|
||||||
|
(define sevenbase (cons 1 '()))
|
||||||
|
(define sevenmid (cons sevenbase sevenbase))
|
||||||
|
(define seven (cons sevenmid sevenmid))
|
||||||
|
(count-pairs seven) ; => 7
|
||||||
|
|
||||||
|
;; and for the great finale...
|
||||||
|
(define finale-a (cons 'a '()))
|
||||||
|
(define finale-b (cons 'b finale-a))
|
||||||
|
(define finale-c (cons 'c finale-b))
|
||||||
|
(set-cdr! finale-a finale-c)
|
||||||
|
;; (you can do this with a single cons cell, actually)
|
||||||
|
|
||||||
|
;; 3.17
|
||||||
|
;; it seems that eq? really does simply check for
|
||||||
|
;; pointer equality - if literally the same cons
|
||||||
|
;; cell is passed twice it returns #t but if two
|
||||||
|
;; cons cells with the same values are created
|
||||||
|
;; they measure #f.
|
||||||
|
|
||||||
|
;; it's honestly very convenient to know this
|
||||||
|
;; it simplifies and clarifies a lot of things.
|
||||||
|
|
||||||
|
;; we can use this to essentially build a list of
|
||||||
|
;; all pairs we have ever visited. We can have this
|
||||||
|
;; list behave like a set - which we defined before.
|
||||||
|
|
||||||
|
;; I used a hash table instead because they were available.
|
||||||
|
;; and efficient, I guess.
|
||||||
|
|
||||||
|
;; You can count the number of pairs without falling
|
||||||
|
;; for cycles by just refusing to traverse a cell
|
||||||
|
;; that has already been traversed, though this
|
||||||
|
;; requires extra storage.
|
||||||
|
;; I'm gonna count this for 3.18, as the logic
|
||||||
|
;; is incredibly similar.
|
||||||
|
|
||||||
|
|
||||||
|
(define (count-pairs-2 x)
|
||||||
|
(define table (make-eq-hashtable))
|
||||||
|
(define (mark-visited! c)
|
||||||
|
(set-cdr! (hashtable-cell table c #t) #t)
|
||||||
|
#t)
|
||||||
|
(define (visited? x)
|
||||||
|
(eq-hashtable-ref table x #f))
|
||||||
|
(define (loop x)
|
||||||
|
(when (and (pair? x) (not (visited? x)))
|
||||||
|
(mark-visited! x)
|
||||||
|
(loop (car x))
|
||||||
|
(loop (cdr x))))
|
||||||
|
(loop x)
|
||||||
|
(vector-length (hashtable-values table)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user