213 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
			
		
		
	
	
			213 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Common Lisp
		
	
	
	
	
	
;; I'm using common lisp from this point on,
 | 
						|
;; I honestly kind of got bored with scheme.
 | 
						|
;; CL is pretty good though. using scheme now.
 | 
						|
 | 
						|
;; well, this means we gotta reimplement
 | 
						|
;; a lot of the things in the book, because we can't
 | 
						|
;; just copy&paste them. but that's fine.
 | 
						|
 | 
						|
;; as an aside, I probably could get pretty close
 | 
						|
;; to being able to copy-paste with this macro:
 | 
						|
(defun rest-symbol (param-list)
 | 
						|
  (cond
 | 
						|
    ((null param-list)
 | 
						|
     nil)
 | 
						|
    ((consp param-list)
 | 
						|
     (cons (car param-list) (rest-symbol (cdr param-list))))
 | 
						|
    ((symbolp param-list)
 | 
						|
     (list '&rest param-list))
 | 
						|
    (t (error "non-symbol as tail element of parameter list."))))
 | 
						|
(defmacro define (name &body body)
 | 
						|
  (cond
 | 
						|
    ((symbolp name) `(defparameter ,name ,@body))
 | 
						|
    ((listp name) `(defun ,(first name)
 | 
						|
		       ,(rest-symbol (rest name))
 | 
						|
		     ,@body))
 | 
						|
    (t (error "Whoops, cannot expand define"))))
 | 
						|
;; This essentially allows us to use scheme-style
 | 
						|
;; define syntax for defining variables and
 | 
						|
;; procedures.
 | 
						|
;; I won't be using this for every single exercise though,
 | 
						|
;; cuz that's kinda boring.
 | 
						|
 | 
						|
 | 
						|
(defun memq (item l)
 | 
						|
  "This definition doesn't have many differences from the book."
 | 
						|
  (cond
 | 
						|
    ((null l) nil)
 | 
						|
    ((eq item (car l)) l)
 | 
						|
    (t (memq item (cdr l)))))
 | 
						|
 | 
						|
(memq 'apple '(pear banana prune)) ;; => NIL
 | 
						|
(memq 'apple '(x (apple sauce) y apple pear)) ;; = (APPLE PEAR)
 | 
						|
 | 
						|
;; EX 2.54
 | 
						|
(defun my-equal? (a b)
 | 
						|
  "fun fact: when I first began common lisp, I used to be kind of annoyed/afraid
 | 
						|
of defining functions recursively like this. I thought this would be less efficient
 | 
						|
than using a loop like in C.
 | 
						|
 | 
						|
Now I know better of course. On SBCL, this is fully tail call optimised,
 | 
						|
and therefore can be used on lists of any length with no fear for
 | 
						|
stack overflow. It generates an iterative process, despite being \"recursive\"
 | 
						|
so this is actually as efficient as can be."
 | 
						|
  (cond
 | 
						|
    ((eq a b)  t)
 | 
						|
    ((and (listp a) (listp b))
 | 
						|
     (if (my-equal? (car a) (car b))
 | 
						|
	 (my-equal? (cdr a) (cdr b))
 | 
						|
	 nil))
 | 
						|
    (t nil)))
 | 
						|
 | 
						|
 | 
						|
;; Wooooo! symbolic derivation.
 | 
						|
;; ex 2.56 is inside here somewhere
 | 
						|
 | 
						|
(defun var= (v1 v2)
 | 
						|
  (and (symbolp v1) (symbolp v2) (eq v1 v2)))
 | 
						|
 | 
						|
(defun var!= (v1 v2)
 | 
						|
  (and (symbolp v1) (symbolp v2) (not (eq v1 v2))))
 | 
						|
 | 
						|
(defun sump (e)
 | 
						|
  (and (listp e) (eq '+ (car e))))
 | 
						|
 | 
						|
(defun addend (e)
 | 
						|
  (second e))
 | 
						|
(defun augend (e)
 | 
						|
  ;; 2.57
 | 
						|
  (if (> (length e) 3)
 | 
						|
      `(+ ,@(cddr e))
 | 
						|
      (third e)))
 | 
						|
 | 
						|
(defun productp (e)
 | 
						|
  (and (listp e) (eq '* (car e))))
 | 
						|
(defun multiplier (e)
 | 
						|
  (second e))
 | 
						|
(defun multiplicand (e)
 | 
						|
  ;; 2.57
 | 
						|
  (if (> (length e) 3)
 | 
						|
      `(* ,@(cddr e))
 | 
						|
      (third e)))
 | 
						|
 | 
						|
(defun number= (a b)
 | 
						|
  (and (numberp a) (numberp b) (= a b)))
 | 
						|
 | 
						|
(defun make-sum (a b)
 | 
						|
  (cond
 | 
						|
    ((and (numberp a) (numberp b)) (+ a b))
 | 
						|
    ((number= a 0) b)
 | 
						|
    ((number= b 0) a)
 | 
						|
    (t `(+ ,a ,b))))
 | 
						|
 | 
						|
(defun make-product (a b)
 | 
						|
  (cond
 | 
						|
    ((and (numberp a) (numberp b)) (* a b))
 | 
						|
    ((number= a 0) 0)
 | 
						|
    ((number= a 1) b)
 | 
						|
    ((number= b 0) 0)
 | 
						|
    ((number= b 1) a)
 | 
						|
    (t (append (list '*)
 | 
						|
	       (if (productp a) (cdr a) (list a))
 | 
						|
	       (if (productp b) (cdr b) (list b))))))
 | 
						|
 | 
						|
(defun expt-p (e)
 | 
						|
  (and (listp e) (eq '** (car e))))
 | 
						|
(defun base (e)
 | 
						|
  (second e))
 | 
						|
(defun exponent (e)
 | 
						|
  (third e))
 | 
						|
 | 
						|
(defun make-expt (b e)
 | 
						|
  (cond
 | 
						|
    ((number= b 0) 0)
 | 
						|
    ((number= b 1) 1)
 | 
						|
    ((number= e 0) 1)
 | 
						|
    ((number= e 1) b)
 | 
						|
    (t `(** ,b ,e))))
 | 
						|
 | 
						|
(defun deriv (expr var)
 | 
						|
  (cond
 | 
						|
    ((numberp expr) 0)	;; c/dx = 0
 | 
						|
    ((var= expr var) 1)	;; dx/dx = 1
 | 
						|
    ((and (symbolp expr) (var!= expr var)) 0)
 | 
						|
    ((sump expr)
 | 
						|
     (make-sum (deriv (addend expr) var)
 | 
						|
	       (deriv (augend expr) var)))
 | 
						|
    ((productp expr)
 | 
						|
     (make-sum (make-product (multiplier expr) (deriv (multiplicand expr) var))
 | 
						|
	       (make-product (multiplicand expr) (deriv (multiplier expr) var))))
 | 
						|
    ;; EX 2.56 - exponentiaton derived.
 | 
						|
    ((expt-p expr)
 | 
						|
     (make-product (exponent expr)
 | 
						|
		   (make-product (make-expt (base expr) (make-sum -1 (exponent expr)))
 | 
						|
				 (deriv (base expr) var))))
 | 
						|
    (t (error "unknown"))))
 | 
						|
 | 
						|
;; 2.58 - okay, so we *could* modify the selectors and stuff
 | 
						|
;; above to make this work, but I kinda wanna keep those.
 | 
						|
;; instead, I'll just make a function that transforms the new
 | 
						|
;; input into the old input format (this is trivial for the
 | 
						|
;; case with fully parenthesized input)
 | 
						|
(defun transform-input (expr)
 | 
						|
  (if (listp expr)
 | 
						|
      (list (second expr) (transform-input (first expr)) (transform-input (third expr)))
 | 
						|
      expr))
 | 
						|
(defun deriv-infix (e v)
 | 
						|
  (deriv (transform-input e) v))
 | 
						|
 | 
						|
;; ... and also kind of doable for the more general case.
 | 
						|
;; requires more work though, but I guess that's the point.
 | 
						|
(defparameter op-precedence (make-hash-table))
 | 
						|
(loop for i in '((+ 1) (* 3) (** 5))
 | 
						|
      do (setf (gethash (car i)  op-precedence) (second i)))
 | 
						|
 | 
						|
(defun prec (op)
 | 
						|
  (gethash op op-precedence))
 | 
						|
(defun collapse (ops items)
 | 
						|
  (if (null ops)
 | 
						|
      (car items)
 | 
						|
      (collapse (cdr ops)
 | 
						|
		(cons (list (first ops) (second items) (first items))
 | 
						|
		      (cddr items)))))
 | 
						|
 | 
						|
;; (3 + 5 * 6 + 2)
 | 
						|
;; (helper 0 expr nil)
 | 
						|
;; (helper 1 '(5 * 6 + 2) '(+) '(3))
 | 
						|
;; (helper 3 '(6 + 2) '(* +) '(5 3))
 | 
						|
;; (helper 1 '(2) '() '(+ (* 6 5) 3))
 | 
						|
;; (+ 3 (* 5 6) 2)
 | 
						|
;; Fuckkkkkkk
 | 
						|
;; this took way longer than it needed to.
 | 
						|
;; not a good-looking implementation at all, really ugly.
 | 
						|
;; but it works! correctly transforms infix notation
 | 
						|
;; to prefix. (output can be directly used by deriv)
 | 
						|
(defun transform-infix (expr)
 | 
						|
  (cond
 | 
						|
    ((null expr) nil)
 | 
						|
    ((or (numberp expr) (symbolp expr)) expr)
 | 
						|
    (t (labels ((helper (expr ops items)
 | 
						|
		  (format t "~a ~a ~a~%" expr ops items)
 | 
						|
		  (cond
 | 
						|
		    ((null expr) items)
 | 
						|
		    ((null (cdr expr))
 | 
						|
		     (collapse ops (cons (transform-infix
 | 
						|
					  (car expr))
 | 
						|
					 items)))
 | 
						|
		    ((>= (prec (second expr)) (or (prec (car ops)) 0))
 | 
						|
		     (helper (cddr expr)
 | 
						|
			     (cons (second expr) ops)
 | 
						|
			     (cons (transform-infix (first expr))
 | 
						|
				   items)))
 | 
						|
		    (t
 | 
						|
		     (helper (cddr expr)
 | 
						|
			     (cons (second expr) nil)
 | 
						|
			     (list (collapse ops
 | 
						|
					 (cons (transform-infix
 | 
						|
						(first expr))
 | 
						|
					       items))))))))
 | 
						|
	 (helper expr '() '())))))
 | 
						|
 | 
						|
(defun deriv-real-infix (e v)
 | 
						|
  (deriv (transform-infix e) v))
 |