Some more progress
This commit is contained in:
		
							
								
								
									
										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.
 | 
			
		||||
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).
 | 
			
		||||
 | 
			
		||||
Note: these are all racket files, I am also learning racket at the same time (and using
 | 
			
		||||
DrRacket) so beware of that. I will mostly try to stick to racket, but there may be 
 | 
			
		||||
times where I switch to `#lang r5rs` or `#lang sicp` for compatability with the book.
 | 
			
		||||
 | 
			
		||||
Also, I will put related-seeming or close-together problems in the same file.
 | 
			
		||||
Note that some of the solutions were done in racket. I started with racket, but eventually
 | 
			
		||||
I switched to common lisp. Right now I'm using Emacs with SLIME, and will hopefully be
 | 
			
		||||
continuing with that for the rest of the book.
 | 
			
		||||
 
 | 
			
		||||
@@ -183,6 +183,7 @@
 | 
			
		||||
;; to the table as well.
 | 
			
		||||
 | 
			
		||||
;; 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)))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user