; Make your DSL expressions scalable
; ------------------------------
; The Little Lisper 3rd Edition
; Chapter 7
; Exercise 5
; Common Lisp
; http://t...content-available-to-author-only...r.com/thelittlelisper
; http://t...content-available-to-author-only...t.com/2010/06/little-lisper-chapter-7-shadows.html
; http://t...content-available-to-author-only...t.com/2010/06/little-lisper.html
; ------------------------------
(setf l1 '())
(setf l2 '(3 + (66 6)))
(setf aexp4 5)
; ------------------------------

(defun notatom (lat)
  (not (atom lat)))
  
(defun sub1 (n)
  (- n 1))  
  
(defun isoperator (a)
  (cond
   ((null a) NIL)
   ((eq a '+) t)
   ((eq a '*) t)
   ((eq a '^) t)
   (t NIL)))

(defun operator (aexp_)
  (car (cdr aexp_)))

(defun numbered? (aexp_)
  (cond
   ((atom aexp_) (numberp aexp_)) ;note use of primitive numberp
   (t (and
       (numbered? (car aexp_))
       (numbered?
        (car (cdr (cdr aexp_))))))))
;numbered? tests whether a representation of an arithmetic expression only contains numbers besides the +, * and ^

(print (numbered? '(1 + 2)))
;T
(print (numbered? '(1 + a)))
;NIL (false)

(defun 1st-sub-exp (aexp_)
  (car aexp_))

(print (1st-sub-exp '(1 + 2)))

(defun 2nd-sub-exp (aexp_)
  (car (cdr (cdr aexp_))))

(print (2nd-sub-exp '(1 + 2)))


;value returns what we think is the natural value of a numbered arithemetic expression
(defun value__ (aexp_)
  (cond
   ((numberp aexp_) aexp_)
   ((eq (operator aexp_) '+)
    (+ (value__ (1st-sub-exp aexp_))
       (value__ (2nd-sub-exp aexp_))))
   ((eq (operator aexp_) '*)
    (* (value__ (1st-sub-exp aexp_))
       (value__ (2nd-sub-exp aexp_))))
   (t
    (^ (value__ (1st-sub-exp aexp_))
       (value__ (2nd-sub-exp aexp_))))))

(print (value__ '(1 + 2)))

;define numbered? for arbitrary length list
(defun numbered_? (aexp_)
  (cond
   ((null aexp_) t)
   ((notatom (car aexp_))
    (and 
     (numbered? (car aexp_))
     (numbered_? (cdr aexp_))))
   ((numberp (car aexp_))
    (numbered_? (cdr aexp_)))
   (t NIL)))
    
(defun numbered? (aexp_)
  (cond
   ((null aexp_) NIL)
   ((isoperator (car aexp_))
    (numbered_? (cdr aexp_)))
   (t nil)))

(print (numbered?'(+ 1 2 3 4 5)))
;T

(print (numbered?'(+ 1 2 3 (* 3 4))))
;T

;define value? for an arbitrary length list
(defun addvec (vec)
  (cond 
   ((null vec) 0)
   ((notatom (car vec))
    (+ (value_ (car vec)) 
       (addvec (cdr vec))))
   (t (+ (car vec)(addvec (cdr vec))))))

(print (addvec '(1 2 3)))
;6

(defun multvec (vec)
  (cond 
   ((null vec) 1)
   ((notatom (car vec))
    (* (value_ (car vec)) 
       (multvec (cdr vec))))
   (t (* (car vec)(multvec (cdr vec))))))

(print (multvec '(1 2 3)))
;6

(defun ^_ (n m)
  (cond
   ((= 0 m) 1)
   (t (* n (^_ n (sub1 m))))))

(^_ 2 3)
;8

(defun value_ (aexp_)
  (cond
   ((numberp aexp_) aexp_)
   ((notatom (car aexp_))
    (value_ (car aexp_))
    (value_ (cdr aexp_)))
   ((eq (car aexp_) '+)
    (addvec (cdr aexp_)))
   ((eq (car aexp_) '*)
    (multvec (cdr aexp_)))
   (t
    (^_ (value_ (1st-sub-expr aexp_))
       (value_ (2nd-sub-expr aexp_))))))

(print (value_ '(+ 3 2 (* 7 8))))
;61 

(print (value_ '(* 3 4 5 6)))
;360
