Some more progress

This commit is contained in:
Emin Arslan 2025-02-22 00:23:47 +03:00
parent 493e14692e
commit 9a365b2ed4
4 changed files with 200 additions and 7 deletions

@ -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

@ -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

@ -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)))