Lisp syntax sheet: quiz 2
; global variable, constant declaration/initialization
(defvar x 10)
(defconstant pi 3.14)

; simple data types and syntax:
;    real numbers, e.g. 5.123
;    integers, e.g. 1024
;    rationals, e.g. 14/3
;    strings, e.g. "foo"
;    characters, e.g. #\c
;    booleans, e.g. t and nil

; prefix style function calls and operations, e.g.
;       (+ (* x y) (- (/ a b) c))
; equivalent of C++ (x*y) + ((a/b) - c)
;
; common math functions:
;    +, -, *, /, tan sin cos sqrt mod ceiling floor expt
; e.g. (expt 2 3) is 2 to the power of 3

; typechecking functions return t (true) if the parameter
;    has the specified type, nil (false) otherwise
; (stringp x) (integerp x) (realp x) (numberp x) (listp x)
; (characterp x) (symbolp x) (functionp x) etc

; function to read and return next item of user input
; (can be number, string, character, list, etc)
(read)

; format can display text, variable, newline (~%), returns nil
(format t "Value in x is ~A~%" x)

; if/else statement to return larger of x and y
;    (skips error checking for numbers in this example)
(if (> x y) x y)

; cond statements take a list of pairs, each has
;    a condition to check and value to return if true
;    t used as final pair's condition since it is always true
(cond
    ((stringp z) (format t "length of string ~A is ~A~%" z (length z)))
    ((listp z) (format t "length of list ~A is ~A~%" z (length z)))
    ((numberp z) (format t "given number, value is ~A~%" z))
    (t (format t "given unexpected value: ~A~%" z)))

; numeric comparison functions: < <= > >= = /=
; string comparisons: string= string> etc
; boolean operators: and or not

; sequence functions (work on lists)
(length L)     ; returns length of list L
(member e L)   ; true if e is element of L, false otherwise
(count e L)    ; counts how often e is in L
(position e L) ; finds first position of e in L

; list syntax '(1 2 3 4) where elements can be any type
; empty list denoted nil or '()
(list x y z)   ; create/return list with elements x, y, z
(dolist (e L) (format t "Next element: ~A~%" e)) ; do something with each element of L
(null L)       ; true iff L is empty list
; more list functions
(car L)        ; returns first element of L
(cdr L)        ; returns list of all the elements in L except the first
(cons e L)     ; return a list with element e followed by elements of L
(reverse L)    ; returned reversed copy of L
(append L1 L2) ; return list with elements of L1 then elements of L2

; examples of higher order functions/calls
(sort '(10 4 1.2 9.5 8) '<=) ; final argument is the comparison function to be used
(funcall 'cons "foo" '(1 2 3)) ; like running (cons "foo" '(1 2 3))
(apply 'cons '("foo" '(1 2 3))) ; also like running (cons "foo" '(1 2 3))
(eval '(cons "foo" '(1 2 3))) ; and also like running (cons "foo" '(1 2 3))
(maplist 'length '(10 20 30)) ; returns '(3 2 1)
(mapcar 'sqrt '(16 4 9)) ; returns '(4 2 3)
(reduce '/ '(120 3 5 2)) ; => 120/3 = 40, then 40/5 = 8, then 8/2 => 4, returns 4
(map 'list '* '(10 20 30) '(5 2 3)) ; => applies * pairwise, giving '(50 40 90)

; example of tail-recursive factorial with an accumulator
(defun factorial (N &optional (sofar 1))
   (cond
      ((not (integerp N)) nil)
      ((< N 1) 0)
      ((= N 1) sofar)
      (t (factorial (- N 1) (* N sofar)))))

; sample let-over-(labels-over-)lambda for a stored integer
;    with sample local functions
(defun buildStoredInt (&optional (orig 0))
   (let  ( ; local variables
           (stored 0)  ; just a valid stored integer, defaults to 0
         )
      (labels
         ( ; local functions
            (setNew (v) (if (integerp v) (setf stored v))) ; sets stored if v a valid int
            (incr () (setf stored (+ stored 1))) ; increments stored value
            (decr () (setf stored (- stored 1))) ; decrements stored value
            (disp () (format t "~A~%" stored))   ; displays stored value
         )
         (setNew orig) ; try to initialize stored from orig
         ; build and return dispatcher as lambda function
         (lambda (cmd &optional (val 0))
            (cond
                ; run whichever local function corresponds to the caller's command
                ((equalp cmd 'increment) (incr))
                ((equalp cmd 'decrement) (decr))
                ((equalp cmd 'display) (disp))
                ((equalp cmd 'set) (setnew val))
                (t (format t "Error: invalid command ~A~%" cmd)))))))

; calls to buildStoredInt
(defvar x (buildStoredInt)) ; build dispatcher using orig's default value of 0 for stored
(defvar y (buildStoredInt 15)) ; build dispatcher using value 15 for stored
(defvar z (buildStoredInt "foo")) ; build dispatcher, setting "foo" fails, stored still 0

; uses of resulting dispatchers (calls to the lambdas to update content)
(funcall x 'increment) ; increments x's stored value (to 1)
(funcall y 'display)   ; displays y's stored value (15)
(funcall x 'decrement) ; decrements x's stored value (back down to 0)a
(funcall z 'set 5)     ; set z's stored value (to 5)