(use-package 'sb-cltl2)
(shadow 'abs)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro assert_good_x ()
  '(assert x))

(defun car+cdr (x)
  (assert_good_x)
  (cons x x))

(car+cdr t)
(car+cdr nil)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro abs (x)
  `(if (minusp ,x)
       (- ,x)
       ,x))

(defun taxi-dist (x y z)
  (+ (abs x)
     (abs y)
     (abs z)))

(defun ack (m n)
  (cond
    ((zerop m) (1+ n))
    ((zerop n) (ack (1- m) 1))
    (t (ack (1- m)
	    (ack m (1- n))))))

(format nil "~S"
	(macroexpand-1 '(abs (realpart (ack 3 #C(8 0))))))

(defun abs+1 (x)
  (abs (incf x)))
(abs+1 0)

(ack 3 #C(11 0))
(abs (realpart (ack 3 #C(11 0))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(shadow 'abs)

(defmacro abs (x)
  `(let ((v ,x))
     (if (minusp v)
	 (- v)
	 v)))

(macroexpand-1
  '(abs (realpart (ack 3 #C(8 0)))))

(defmacro abs (x)
  `(let (v)
     (setf v ,x)
     (if (minusp v)
	 (- v)
	 x)))

(defmacro when-car=cdr
    (x &body body)
  `(let ((v ,x))
     (when (= (car v)
	      (cdr v))
       ,@body)))

(let ((v "They are equal!"))
  (when-car=cdr (cons 5 5)
    (princ v)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro when-car=cdr
    (x &body body)
  (let ((v (gensym)))
    `(let ((,v ,x))
       (when (= (car ,v)
		(cdr ,v))
	 ,@body))))

(format nil "~S"
	(macroexpand-1 '(when-car=cdr p (write p))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun symify (s)
  `(,s (gensym)))
(defmacro with-gensyms
    (syms &body body)
  `(let ,(mapcar #'symify
		 syms)
     ,@body))

(defmacro crow-dist (x y)
  (with-gensyms (a b)
    `(let ((,a ,x)(,b ,y))
       (sqrt
	 (+ (* ,a ,a)
	    (* ,b ,b))))))

(format nil "~S"
	(macroexpand-1 '(crow-dist x y)))

(taxi-dist 3 4 0)
(crow-dist 3 4)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro det+?
    ((x1 y1) (x2 y2)
     &body body)
  `(when (plusp
	   (- (* ,x1 ,y2)
	      (* ,x2 ,y1)))
     ,@body))

(defun plus-list (a b c d)
  (det+? (a b)
	 (c d)
     (list a b c d)))

(plus-list 3 4 5 6)  ; 3 * 6 - 4 * 5 = -2
(plus-list 4 3 5 6)  ; 4 * 6 - 3 * 5 = +9

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro argc (&rest args)
  `(if ,(null args)
       0
       (1+ (argc
	     ,@(rest args)))))

(defmacro argc (&rest args)
  (if args
      `(1+ (argc
	     ,@(rest args)))
      '0))

(macroexpand '(argc :a))
(macroexpand '(argc))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defmacro both+? (a b)
  `(and (plusp ,b)
	(plusp ,a)))
(let ((x -1) (y -1))
  (both+? (incf x) (incf y))
  (format nil "X=~S, Y=~S" x y))
