A couple lisp Notes:

default

Links
 
Todo - find all +** and create examples.

;;;;;
;; rlwrap sbcl
;; rlwrap can be used to get readline's line editing, persistent
;; history and completion on a nix system. Run rlwrap sbcl
;; instead of just sbcl!
;;;;;

;; *** Some of this may be implementation specific
;; *** whether clisp, sbcl, etc

;; nil is both an atom and a list

;; The lisp reader translates text into lisp objects.
;; The lisp evaluator deals with these objects.
;; In other words the lisp reader can take:
15
30/2
#xf
;; It will translate these to the same object,
;; before it reaches the lisp evaluator.

(setq *print-case* :capitalize)
;; Sets output to be Capitals instead of default :upcase [:downcase can also be used] 

;; :q
;; in case clisp starts acting crazy after a mistake

;; cntrl-c :a
;; Exit an infinite loop
;; :a = abort

;; :a
;; abort, when running into error

(trace sum-func-name)
;; Turn on tracing output of a function when it is run

(untrace sum-func-name)
;; Turn off tracing of a function

;; :bt
;; backtrace when running into error

(error "oh no! blah blah")
;; Throw an error on purpose, with a message of "oh no..."

(define-condition omg () ()
  (:report (lambda (condition stream)
             (princ "OMG! Stop screwing up" stream))))
(error 'omg)
;; Create a custom condition and trigger it with error.
;; 
(defun jacked-function ()
  (error 'omg))
(handler-case (jacked-function)
  (omg () "Don't bother me!")
  (oh-yeah () "Call me any time."))
;; Intercept condition with a 'handler-case', this
;; stops the REPL from erroring out, and let's the
;; program keep running.

(unwind-protect (/ 1 0)
  (princ "Even dividing by zero can't stop me! buhaaahahaha"))
;; Use 'unwind-protect' to execute crucial code even after an
;; error was aborted.

*
;; Is set to the last evaluation [last returned value]
;;
(print "test")
*
;; Would evaluate to "test" [returns "test"]

(directory "./")
;; Show current working directory in clisp

(directory "./*")
;; List files in current working directory

(ext:dir)
;; Show files in current working directory in clisp (name, size, date created) 

(load "chosen-file.cl")
;; Load a file into clisp interpreter

;; clisp -i chosen-file.cl
;; clisp -init-file chosen-file.cl
;; Loads files at startup, running clisp from shell.

(compile-file "chosen-file.cl")
;; Compile file from inside lisp [fas file must be loaded afterwards]
(load "chosen-file.fas")

;; clisp -c file-name.cl
;; Compile lisp file

(compile 'this-function)
;; A defined function in the interpreter can be compiled, by
;; giving it's name

#||
Multiline comment in your face
||#

;
;; above is an inline comment usually after some code

;;
;; Comment for code that follows and is indented
;; the same as the code, like in the body of
;; a function or macro

;;;
;; Comment that is a paragraph explaining a
;; large amount of code

;;;;
;; File header comment (for describing your file)

(sleep 20)
;; Sleep for 20 seconds

(sleep (* 1 60))
;; Sleep for one minute

(defun sleep-minutes (m)
  (sleep (* m 60))
(sleep-minutes 2)
;; Define a sleep function and use it to sleep for 2 minutes.

(defun add-em-up (x y)
  "Add two numbers, it's fun"
  (format t "Wow adding ~d plus ~d is great!!.~%" x y)
  (+ x y))
;; Example of using a documentation string. [the second line]
;; That can be called like below. Acts as a comment to
;; describe the function.

(documentation 'add-em-up 'function)
(documentation 'defun 'function)
;; Display the documentation string of a function.

;; *global-variable*
;; *..* is used to represent variables

;; +constant+
;; +..+ is used for constants

;; %low-level-function%
;; %%low-level-function%%
;; %..% and %%..%% used for low level functions
;; These naming convetions are not required but many
;; use them.

;; -
;; Used to seperate two words compouned as a function, variable
;; or macro name, as in happy-days.

;; ->
;; Functions that convert one kind of value to another
;; use -> in the name, instead of a -


"hello, world"
(format t "hello, world")
(write-line "hello, world")
(print "hello, world")
;; Hello worlds
;; Print prints out in a form that can be read by the lisp reader

(defun hello-world () (format t "hello, world"))
;; Hello world function

(defun kitty
  (color nickname &optional size cool-or-not)
  (list color nickname size cool-or-not))
(kitty "orange" "morangki")
(kitty "black" "blacki" "little")
(kitty "brown" "beaki" "fluff" "annoying")
;; Function with optional parameters, the first two
;; are required, the 3rd and 4th are optional.

(defun virgin-drinks (&optional (a "bloody mary") b) (list a b))
(virgin-drinks "shirley temple")
(virgin-drinks "daiquiri" "pina colada")
;; Optional parameter with default value if left out
;; when calling the function.

(defun find-date (backup-date &optional (new-date backup-date))
  (list backup-date new-date))
(find-date "ariana" "taizya")
(find-date "ariana")
;; Use the first parameter as the default to the second,
;; if the second one is not supplied.

(defun meals-today (bfast lunch &optional (dinner "torta" dinner-supplied-p))
  (list bfast lunch dinner dinner-supplied-p))
(meals-today "pigeon egg" "rat sandwich" "opossum steak")
(meals-today "armadillo eggs" "kangaroo toes")
;; Blah-blah-supplied-p will return true if arguement is supplied,
;; otherwise it returns NIL, revealing that the default
;; value was used.

call-arguments-limit
;; Will shows how many options your lisp
;; implementation will allow

(defun girlfriends (&key never-again so-so good oh-yes)
       (list never-again so-so good oh-yes))
(girlfriends :oh-yes "kat")
(girlfriends :oh-yes '("kat" "megan"))
(girlfriends :never-again "sarah" :so-so "beth" :good "nadjmeh" :oh-yes "kat")
;; Keyword parameters, let you set value by :keyword

(defun love-is (&key (a "over")
                     (b "imagined" b-supplied-p)
                     (c (concatenate 'string a b)))
  (list a b c b-supplied-p))
(love-is)
(love-is :a "me")
(love-is :a "me" :b "now" :c "mine")
;; Keywords can also use -supplied-p to inform
;; whether a parameter was supplied or is using
;; the default.

(function chosen-function)
#'chosen-function
;; Allows you to get a function object
;; The #' is the short form of function

(funcall #'chosen-function)
(chosen-function)
;; Two ways to call a function

(apply #'chosen-function some-list)
;; Apply is like funcall except it expects it's
;; input to be a list

(funcall #'+ (values 4 8) (values 3 9))
;; Funcall calls a function, but can only see
;; the primary values passed.

(multiple-value-call #'+ (values 4 8) (values 3 9))
;; Like funcall, but can see all the values passed to it.

(multiple-value-bind (x y z) (values 15 15 15)
  (+ x y z))
;; Accepts multiple return values.

(multiple-value-list (values 2 4 6 8))
;; Collects into a list

(values-list (multiple-value-list (values 2 4 6 8)))

(defparameter *taco* nil)
(defparameter *julios* nil)
(setf (values *taco* *julios*) (floor (/ 85 53)))
*taco*
*julios*
;; Using setf on values.

(list 4 5 6)
;; Create a list (4 5 6)

(list :x 4 :y 5 :z 6)
;; Create a plist [property list] (:X 4 :Y 5 :Z 6)

(getf (list :x 4 :y 5 :z 6) :y)
;; Get value by keyword symbol in a plist

;;;;;;;;;;;;;;;;;;
;; Lisp Predicates

(atom "am i an atom bomb?")
(atom 23)
(atom t)
(atom '(is me an atom too?))
(atom nil)
;; Check to see if datum type is an atom
;; Will return T or nil
;; nil is an atom and a list

(listp "am i a list")
(listp nil)
(listp 23)
(listp '(better say I'm a list!))
;; Will return t if its argument is a list
;; nil is a list and an atom

(numberp 666)
(numberp 'spooky-number!)
;; Returns T if argument is a number else returns nil

(null nil)
(null '(cold hearted))
(null '())
(null (cdr (cdr (cdr '(me-a-freak?)))))
(null (cdr (cdr (cdr '(me a freaky?)))))
(null (car '(z a t a r a n)))
;; Returns t if its argument is nil

(zerop 0)
(zerop 1)
(zerop (- 76 76))
(zerop (car (cdr (cdr '(8 0 0)))))
(zerop (car '(9 0 0)))
;; Returns true if its argument is 0

(equal 'me 'me)
(equal 'me 'myself)
(equal nil nil)
(equal 'you '(you))
(equal (cdr '(r a d)) '(a d))
;; Compare data to see if they have the same value
;; Returns T if its arguments have the same value

(< 10 20)
(< .5 .9)
;; Less-pee returns true if its 1st argument is less than its 2nd

(> 20 10)
(> (car (cdr '(8 7 7))) 6)
;; Greater-pee returns true if 1st argument is > that its 2nd

;; end-lisp-predicates
;;;;;;;;;;;;;;;;;;;;;

(remove-if-not #'oddp '(1 2 3 4 5 6 7 8 9))
;; Create a new list with all non odd numbers removed
;; #' = forces lisp to look up a function name
;; rather than a variable name
;; Could also be writte as:
(remove-if-not #'(lambda (x) (= 1 (mod x 2))) '(1 2 3 4 5 6 7 8 8 9))

(defun gtr-six-ft-dwarf-stackp (m1 m2)
  (> (+ m1 m2) 6))
(gtr-six-ft-dwarf-stackp 3.2 2.7)
(gtr-six-ft-dwarf-stackp 4.1 2)
;; Define a predicate function that takes to dwarfs 
;; heights and checks to see if they are taller than 6ft
;; when stacked.
;; Then test two sets of dwarfs.

(defun would-keep-ya (babe)
  (if (> babe 1)
      'Id-keep-ya!
      'Get-back-ugly!))
(would-keep-ya 0)
(would-keep-ya 5)
;; Define a function that would keep any babe that is 
;; rated greater than 1.
;; Then test a few out.

(defun good-enough-guy (salary)
  (cond ((> salary 200000) 'marry-me!)
	((and (> salary 100000) (< salary 200000)) 'hey-big-boy)
	((> salary 70000) 'just-this-once)
	((< salary 50000) 'go-scrubbin-elsewhere)
	(t 'maybe-sometime)))
(good-enough-guy 50000)
(good-enough-guy 40000)
(good-enough-guy 350000)
(good-enough-guy 110000)
(good-enough-guy 75000)
;; Define function to find good enough man based on
;; dolla dolla.
;; t 'maybe-sometime meets all other salaries
;; as t always returns t and will always be evaluated
;; if the cond gets this far. (else case)

(defparameter *bye-bye* (list 0 1 2 0 1 2 0 1))
*bye-bye*
(setf *bye-bye* (delete 2 *bye-bye*))
*bye-bye*
;; Delete is like remove except it destroys. Must
;; be careful when using delete as not to alter
;; shared structure. Normally use remove.

(defparameter *god-of-chaos* (list 0 1 2 3 4 5))
(sort *god-of-chaos* #'>)
*god-of-chaos*
;; Sort is also destructive. In the end *god-of-chaos*
;; may not be what you expected. You may want to make
;; a copy before sorting if original value is still
;; needed.

(defun models (x y z) (list x y z))
(models "hand" "foot" "runway")
;; Define function with three properties

(defun models (&key x y z) (list x y z))
(models :x "hand" :y "foot" :z "runway")
(models :z "runaway" :y "foot" :x "hand")
(models :x "hand" :z "runway")
(models)
;; Define function with optional keyword properties and
;; call them, ignored keywords default to nil
;; & = optional

(defun models (&key x (y "wrist") (z "lingerie" z-p)) (list x y z z-p)
(models :x "hand" :y "foot" :z "runway")
(models :z "runway" :y "foot" :x "hand")
(models :x "hand" :z "runway")
(models)
;; Define function with optional keyword and
;; set default property when not called, also
;; c-p to check if function was called with
;; that property/argument

(cons 1 (cons 2 (cons 3 nil)))
;; Lists in lisp are made out of cons cells, terminated by a nil

(cons 8 (cons 6 4))
;; If the list is not terminated by a nil, it is considered a dotted-list
[8 6 . 4]

(cons 5 (cons 4 (cons 2 3)))

(defparamater *a-global-var* 10)
;; defines global variable (that is overwritable)
;; Dynamic variables are global [special]
;; Referenced from anywhere, anytime
;; It has to be given a value. [Can not be defined unbound, with defparameter]

(defparamater *a-global-var* 10
              "Global with document string")
;; Document strings can be added to dynamic variables [global]

;; *are called earmuffs* they are optional,
;; but used to identify as a special variable, rather than lexically scoped.

(defvar *fi* 4)
;; Defines a global variable (that is not overwritable)
;; Although it can be changed with setf.
;; It will not give error if you try to change value,
;; it will just ignore it: (defvar *fi* 5) is still = 4
;; Defvar can also create unbound variables.
;; Variables with no initial value.
(defvar *empty-now*)

(defvar *fu*)
;; Defines *fu*, but does not set it.
(defvar *fu* 3)
;; In this case it would set, but now it can not be overwritten.
;; Keep in mind it can be changed with setf

(defvar *whatya-doin* "studying")
(defun come-over () (format t "I'm busy: ~a~%" *whatya-doin*))
(come-over)
(let ((*whatya-doin* "partying")) (come-over))
(come-over)
(defun excuses ()
  (come-over)
  (let ((*whatya-doin* "partying")) (come-over))
  (come-over))
(excuses)
;; Example of using global/dynamic variables and changing
;; values whithin a binding/scope and the value being
;; the original once out of scope.

(defun decide ()
  (format t "After deciding~14t: ~a~%" *whatya-doin*)
  (setf *whatya-doin* "not sure")
  (format t "Before deciding~14t: ~a~%" *whatya-doin*))
(decide)
(excuses)

(defconstant +sassy+ "yeah right!")
;; defconstant
;; Defines a constant, can not be changed
(setf +sassy+ "check your attitude")
;;## Compile-time error:
;;##  +SASSY+ is a constant and thus can't be set.

(setq cool "me")
;; Set symbol/variable 'cool' to "me"
;; Setq is an operator
;; Setq creates a special/dynamic variable

(setf good-num (+ 13 10))
;; Set symbol/variable 'good-num' to '23' 
;; Setf is a macro
;; Setf and setq act the same when setting variable values.
;; Setf has other functions also, that setq does not
;; Setf uses setq when setting variables.

(setf fname "joe" lname "mammy")
;; Setf can set more than one variable at a time.

(setf my-fav-num (setf your-fav-num (random 100)))
;; Set two variables at the same time to the
;; same value.

(setf homosapien "everyone")
;; Set a variable

(setf (aref homosapien 2) #\u)
;; Setf for an array
;; Aref access elements of an array

(defparameter *who-you-gonna-call* (make-hash-table))
;; Create a hashtable

(setf (gethash 'person *who-you-gonna-call*) "yodaddy")
(setf (gethash 'phone-number *who-you-gonna-call*) '555.555.555)
;; Set a slot/field in a hashtable

(gethash 'phone-number *who-you-gonna-call*)
;; Retrieve a key from a hashtable

(defparameter *head* (make-hash-table))
(gethash 'big *head*)
(setf (gethash 'big *head*) 'pumpkin)
(gethash 'big *head*)

(defparameter *classmates* (make-hash-table))
(setf (gethash 'smart *classmates*) 'susie)
(defun student-present (key hash-table)
  (multiple-value-bind (value present) (gethash key hash-table)
    (if present
      (format nil "Student ~a is here and alert." value)
      (format nil "Student ~a is skipping." value))))
(setf (gethash 'class-clown *classmates*) nil)
(student-present 'smart *classmates*)
(student-present 'class-clown *classmates*)
(student-present 'genius *classmates*)
;; Use of multiple return value, to allow you to see if
;; a value actually exists and is set to nil, or if it
;; does not exist. In this case skipping means, it does
;; not exist.

(maphash #'(lambda (k v)
             (format t "~a => ~a~%" k v))
         *classmates*)
;; Maphash like map/mapcar iterates over a hash. This
;; example prints out the key value pairs in a hash.

(loop for k being the hash-keys in *boys-rating* using (hash-value v)
      do (format t "~a => ~a~%" k v))
;; Print out key value pairs with a loop, instead of maphash.

(loop for ltr in '(j o e m a m m y)
   do (print ltr))
;; Iterate a list printing each element

(loop for x in '(d i i m o u)
      for y in '(o t n e r s)
      collect (list x y))
;; Iterate two lists in parallel
;; collecting them into a list of sets of two.

(loop for x in '(d i i m o u)
      for y in '(o t n e r s)
      append (list x y))
;; Iterate to lists in parallel
;; appending them into a single list.
;; Could also use: nconc (in place of append)

(loop for egg from 1 to 6
      for triplets = (* egg 3)
      collect triplets)
;; Iteration with a counter

(loop for ball-color in '(yellow blue red purple orange green)
      for num from 1
      when (> num 1)
      do (format t ", ")
      do (format t "~A->~A" num ball-color))
;; Iterate a list in parallel with a counter
;; to seperate the billard ball numbers and color
;; sets from the next with a comma.
;; Would be possible to use an "if" instead of "when".

(loop for nose in '(big giant wide missing small thin)
      until (equal nose 'missing)
      collect (list nose 'smelt-that))
;; End a loop early with until

(loop for handout from 1
      for x = (* handout 10)
      while (< x 51)
      do (prin1 "I am giving out ")
      (print (* handout 9))
      collect x)
;; Use a while to terminate a loop

(loop for num in '(8 7 6 5 4 3 2 1)
   collect (loop for x from 1 to num
     collect x))
;; Loop inside a loop

(loop for (food animal) in '((grass cow) (bone dog) (leaf bug))
      collect (list animal food))
;; Swap list values around by destructuring with a loop

(loop for (person . work) in '((judy . artist)
          (robin . teacher)
          (raul . singer))
        collect work)
;; Destructure a dotted list grabbing values

(let ((code "227700abc"))
  (loop for j from 0 below (length code)
    for ch = (char code j)
    when (find ch "abcdefghijklmnopqrstuvyxyz" :test #'eql)
    return ch))
;; Exit the loop when if finds a lowercase letter in the code
;; Return the character that made the loop exit.

(loop for x in '(2 3 4 5)
  never (equal x 1))
;; Return T if 1 is not in list of loop

(loop for drink in '(rum vodka scotch whiskey)
  thereis (equal drink 'scotch))
;; Check to see if a value is in the looped list

(loop for mono in '(vjay vjay vjay vjay)
   always (equal mono 'vjay))
;; Make sure always the same person in looped list

(loop for die-side upto 20 collect die-side)
(loop for die-side from 0 downto -20 collect die-side)
;; Print out 0-20

(do ((list nil) (tail nil) (die-side 0 (1+ die-side)))
  ((> die-side 20) list)
  (let ((new (cons die-side nil)))
    (if (null list)
      (setf list new)
      (setf (cdr tail) new))
    (setf tail new)))
;; This is equivalent to the above loop.


(loop for location in (list "Downtown" "5th Ward" "Galleria")
      collect location)
;; Loop through a list

(loop for every-other in (list 1 2 3 4 5 6 7 8 9) by #'cddr collect every-other)
;; Using 'by' you can call upon a function to act on the loop.

(loop for cons-cell on (list "me" "myself" "I") collect cons-cell)
;; On loops by cons cell.

(loop for every-other-cons-cell
      on (list "me" "myself" "I")
      by #'cddr
      collect every-other-cons-cell)
;; Use by with on.

(loop for vector-elements across "rawr" collect vector-elements)
;; Use across for vectors.

(loop repeat 10
      for x = 5 then y
      for y = 10 then (+ x y)
      collect y)
;; Repeat a loop a certain number of times.

(loop repeat 10
      for y = 10 then (+ x y)
      for x = 5 then y
      collect y)
;; Repeat a loop a certain number of times.

(loop repeat 10
      for x = 5 then y
      and y = 15 then (+ x y)
      collect y)
;; 'And' can replace nested fors.

(loop for (x y z) in '((10 10 10) (20 30 40) (15 30 45))
      do (format t "x:~a y:~a z:~a~%" x y z))
;; Destructuring with a loop.

(loop for cons on (list 5 6 7 8 9)
      do (format t "~a" (car cons))
      when (cdr cons) do (format t ", "))
;; Comma seperate a list with a loop.

(loop for (item . rest) on (list 5 6 7 8 9)
      do (format t "~a" item)
      when rest do (format t ", "))
;; Comma seperate a list with a dotted parameter.

(loop for num upto 5 append (list num num num))
;; Append to a list.

(loop for num upto 5 nconc (list num num num))
;; Nconc is a destructive append.

(loop for num from 5 to 12 do (print num))
;; Looping with do.

(block secret
       (loop for message from 0 return "not telling")
       (print "Are you telling the secret?")
       "The secret is loose!")
;; Make it till the end of the loop.

(block secret
       (loop for message from 0 do (return-from secret "not telling"))
       (print "Are you telling the secret?")
       "The secret is loose!")
;; Returns not telling, and exits the loop.

(loop for even-num from 1 to 20 do
      (when (evenp even-num) (print even-num)))
;; Print only even numbers with a loop.

(loop for even-num from 1 to 20 when (evenp even-num) sum even-num)
;; Sum even numbers from 1 to 20

(loop named get-em for list in '((1 21 33) (43 5 6)) do
      (loop for item in list do
            (if (evenp item)
              (return-from get-em item))))
;; Name a loop and return from it.
;; The name must be the first clause.

;; Loop Kewords:
;; collecting summing counting, do, finally

;; Counting words:
;; for, as

;; from, downfrom, upfrom

;; equals-then
;; in, on

;; Setting local variables:
;; with

;; Accumulation words:
;; collect, append, nconc, count, sum, maximize, minimize

;; Append and nconc work on lists.

;; Return words:
;; return, return-from

;; Conditional words:
;; if, when

;; Termination words:
;; while, until, always, never, thereis
;; loop-finish
 
;; While and until, will execute the epilogue of a loop.
;; While terminates the first time the test is false.
;; Until stops the first time test is true.
 
;; Loop-finish runs the epilogue of a loop.
 
;; Always, never, thereis terminate the loop immediately,
;; never running into other loops or the epilogue.

(if (loop for num in '(2 4 6 8) always (evenp num))
  (print "All numbers are even."))
;; Check to see if all numbers are even.

(if (loop for num in '(1 3 5 7 9) never (evenp num))
  (print "You got all odds!"))
;; Check to see if all numbers are odd, using never.

(loop for character across "xyz789" thereis (digit-char-p character))
;; Thereis exits upon finding it's match [a digit].

(loop for character across "xyzbbc" thereis (digit-char-p character))
;; Thereis returns nil by default, if not finding a match.

(defparameter *random-num* (loop repeat 200 collect (random 20000)))
(loop for number in *random-num*
      counting (evenp number) into even-nums
      counting (oddp number) into odd-nums
      summing number into total-summed
      maximizing number into max-num
      minimizing number into min-num
      finally (return (list min-num max-num total-summed even-nums odd-nums)))
;; While looping:
;; Counting collect how many.
;; Summing sums
;; Maximizing - gets highest number
;; Minimizing - collects lowest number

(defparameter *boys-rating* (make-hash-table))
(setf (gethash 'dustin *boys-rating*) 5)
(setf (gethash 'george *boys-rating*) 3)
(setf (gethash 'sam-the-man *boys-rating*) 6)
(setf (gethash 'bilian *boys-rating*) 8)
(setf (gethash 'vlado *boys-rating*) 9)
(maphash #'(lambda (k v) (when (< v 6) (remhash k *boys-rating*))) *boys-rating*)
;; Remove pairs with rating less than 6

;; clrhash - completely clears a hash table of all key/value pairs

(setf quantity 0)
(setf quantity (+ quantity 1))
(incf quantity)
(setf quantity (- quantity 1))
(decf quantity)
(setf quantity (+ quantity 5))
(incf quantity 5)
;; Changing a value, with +/- and incrementing
;; and decrementing.
;; Decf and incf are modify macros. [Macros built
;; on top of setf, that modify values based by
;; those values]

(setf girl-name "george")
(setf boy-name "allison")
(rotatef girl-name boy-name)
;; Rotatef rotates/switches the values.
;; The longer version would be this:
(let ((temp-name girl-name)) (setf girl-name boy-name boy-name temp-name) nil)

(setf name1 "me" name2 "myself" name3 "I")
name1
name2
name3
(shiftf name1 name2 name3)
name1
name2
name3
(shiftf name1 name2 name3)
name1
name2
name3
;; Shiftf shifts the values to the left.
;; In the end all the name1-3 will be: I
;; To get the end result one could:
(let ((temp-name name1)) (setf name1 name2 name2 name3) temp-name)

(let (var declaration)
  ...local area that can use lets above...)
;; Define local variable
;; Static variables are local [lexical]
;; Can only be referenced within construct [scope].

(let ((x 6))
  x)
;; Lexical scope with let.

(let ((z 90))
  (+ 45 z))

(let ((polygirl "Oh! You brought me a play toy!")
      (monogirl "WTH! I'll kill you!")
      (play-toy "Look what I got you for your birthday... "))
  (print "A polygirl responds: ")
  (princ polygirl)
  (print "A monogirl responds: ")
  (princ monogirl))
;; Example of let creating local variables

(defun boyfriend (him)
  (format t "Steady Boyfriend: ~a~%" him)
  (let ((him "Vlado"))
    (format t "Last night's boyfriend: ~a~%" him)
    (let ((him "Bilian"))
      (format t "Tonight's boyfriend: ~a~%" him))
    (format t "Last night's boyfriend: ~a~%" him))
  (format t "Steady Boyfriend: ~a~%" him))
(boyfriend "Mekel")
;; Let changing the boyfriend variable, inside the function.
;; Call with (boyfriend "chosen-name")
;; Binding forms, introduce new variables that are only usable
;; within a construct, in this case a function.

(let ((me "myself and I")) (format t "~a" me))
((lambda (me) (format t "~a" me)) "myself and I")
;; This let is similar to the anonymous function
;; below it.

(defun fun-name (args))
;; Defines global functions

(defun square-it (x)
  (* x x))
(square-it 8)
;; Define a function to square numbers, then use it on 8

(defun lego-stud-count (length width)
             (* length width))
(lego-stud-count 2 5)
;; Define function to find how many studs are
;; on a lego piece.

(defun lego-stud-count (len wid &optional (glued-on 0))
  (* (+ len glued-on) (+ wid glued-on)))
(lego-stud-count 2 5)
(lego-stud-count 2 5 1)
;; Define function with an optional argument

(defun lego-stud-count (len wid &key (glued-on-len 0) (glued-on-wid 0))
  (* (+ len glued-on-len) (+ wid glued-on-wid 0)))
(lego-stud-count 2 5 :glued-on-len 1)
(lego-stud-count 2 5 :glued-on-wid 1)
(lego-stud-count 2 5 :glued-on-len 2 :glued-on-wid 3)
;; Define function with key value optional arguements

(defun rect-2d-or-3d (len wid &optional (hgt 1))
  (* len wid hgt))
;; This has an optional argument. Given two values it
;; finds the area of a 2d rectangle. Given three it finds
;; the volume of a 3d rectangle. &optional (hgt 1) lets
;; height be optional, with a default of 1, if nothing
;; is entered.

(defun cookies (raisin &key (chocolate 0) (oatmeal 0) (sugar 0))
  (princ "I am stuck with ")
  (princ (+ raisin chocolate oatmeal sugar))
  (princ " cookies!"))
(cookies 1 :sugar 5 :chocolate 2 :oatmeal 1)
;; Use keywords for arguments with default values, must have : before name
;; when keywords called.

(defun mult-len-wid (len wid &rest listed)
  (print "The list of &rest are")
  (print listed)
  (* len wid))
(mult-len-wid 20 30 'my 'mammy 'and 'me)
;; Rest and the &rest of arguments to al list
;; Will return nil, if no rest values are supplied

(defvar *first-partner* "Denver")
(defvar *second-partner* "Detroit")
(defun debbie-calls (*first-partner*)
  (let ((*second-partner* "Dorah"))
    (print "Debbie calls")
    (princ *first-partner*)
    (print "Debbie calls")
    (princ *second-partner*)
    (print "Debbie devours")
    (debbie-devours (concatenate 'string *first-partner* " and " *second-partner*))))
(defun debbie-devours (debbie-devours-args)
  (princ debbie-devours-args)
  (print "Debbie devours")
  (princ *first-partner*)
  (print "Debbie devours")
  (princ *second-partner*))
(debbie-calls "Deutschland")
(debbie-devours "Eat it Debbie!")
;; Define globals with defvar so 'let' can access them from outside it's
;; scope/construct/reach whatever yous want to call it. This also has a
;; function calling a function. [debbie-calls calls debbie-devours]
;; Also notice debbie-calls accepts an argument that replaces the global
;; variable '*first-partner*' : (debbie-calls "Sarah"). The let in
;; debbie-calls replaces the globalvar '*second-partner*' whose value
;; originally was "Detroit" with "Dorah".

;; (flet ((func_name (args)
;;           ...func body...))
;;   ...area function is usable...)
;; Defines local function

(labels ((a (n)
            (+ n 2))
         (b (n)
            (+ (a n) 4)))
  (b 6))
;; Enables one local function to call another and to also call itself
;; Allows you to define functions locally

;; whitespace is ignored

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defparameter *amansthoughts* (loop for i below 100000 collect 'girls))
;;
(defun lst-length (lst)
  (labels ((f (lst accum)
              (if lst
                (f (cdr lst) (1+ accum))
                accum)))
    (f lst 0)))
;;
(lst-length *amansthoughts*)
;;
;; Example of tail call function, and then using it.
;; f calls itself recursively, and can forget and
;; not put anything on the stack.
;; Notice there is also variable shadowing here:
;; lst, within f, and lst within lst-length
;; *** If using clisp, tail call functions,
;; need to be compiled, for optimization reasons
;;
;; lst-length could also be written with the reduce
;; function, to be more functional in style:
(defun lst-length (lst)                                                    
  (reduce (lambda (x i)                                                    
            (1+ x))                                                        
          lst                                                              
          :initial-value 0))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(ash)
;; arithmetic shift function (halves the result and shortens the result) (binary shift)

(ash 11 1)
22
;; Shift bits left

(ash 11 -1)
5
;; Shift bits right

(princ "yum yum")
;; Print out a string

(cons 'me 'you)
;; Links to pieces of data. In this case two symbols, resulting in the cons cell:
(ME . YOU)

(cons 'me '(you them))
;; Adds a new item to the beginning of a list

(cons 'me (cons 'you (cons 'them ())))
;; Same as the above, just a longer way to write it

(defparameter *con-man* (cons 2 4))
(setf (car *con-man*) 22)
(setf (cdr *con-man*) 44)
*cons*
;; Using setf with the car/cdr of cons cells

(cons 3 nil)
(cons 3 (cons 4 nil))
(cons 4 (cons 5 (cons 6 nil)))

(car '(me myself I))
;; Retrieves first value of a cell

(cdr '(me myself I))
;; Retrieves the remainder of a list (skips the first value)

(cadr '(mouse dog cat shoe))
;; car the cdr. Retrieves only the second item

(cadr '(when (> y 20) (print y)))

(car (cdr '(mouse dog cat shoe)))
;; Same as above

;; cdar

; cddr
(cddr '(when (> y 20) (print y)))

;; caddr

;; cadadr

(defparameter *dissect-me* (list '(0 1 2) '(3 4 5) '(6 7 8)))
*dissect-me*
(car (car *dissect-me*))
(caar *dissect-me*)
(car (cdr *dissect-me*))
(cadr *dissect-me*)
(car (cdr (car (cdr *dissect-me*))))
(cadadr *dissect-me*)

;; These are buit in up to four levels deep.
;; Count the a's and d's and it will tell you
;; how many car's and cdr's are involved.
;; Some must have lists inside of lists
;; to work.

(list 'taco 'mango 'pizza)
;; Creates a list

(defparameter *modme-1* (list 4 5))
(defparameter *modme-2* (list 6 7))
(defparameter *modme-3* (append *modme-1* *modme-2*))
*modme-3*
*modme-2*
(setf (second *modme-2*) 9)
*modme-2*
*modme-3*
;; Append shares the structure of the second item by using it
;; as the cdr of the first. Changing *modme-2* alters *modme-3*

'(taco mago pizza)
;; Same as above, creates a list

'(her (oh yes) that one)
;; Nested list

(if '()
    'am-i-true?
    'or-am-i-false?)
;; An empty list is false

(if t "oh yeah!" "or no..")
;; good

(if nil "nice!" "uh oh")
;; oops

(if "I command you" "you better do it" "make me")
;; Non-nil means true!

() '() 'nil nil
;; Four ways to represent an empty list or false

(if (= (+ 2 2) 4)
    'oh-yeah
    'no-way)

(if (evenp 6)
    'is-even
    'is-odd)

(if (> 7 9) "Of course" "Nada chance")
(if (> 9 7) "Of course" "Nada chance")
;; Simple if then else. One returns then,
;; other the else.

(if (> 7 9) "Oh yeah")
;; Returns NIL as there is now else.

(setf seen-hottie "blondie from other tribe")
(defun caveman-horny-p (x)
  (print "ugh ugh"))
(defun club-back-of-head (x)
  (print "smack"))
(defun enjoy-the-night-with (x)
  (print "huh uh huh uh huh uuuuu..."))
(if (caveman-horny-p seen-hottie)
  (progn
    (club-back-of-head seen-hottie)
    (enjoy-the-night-with seen-hottie)))
;; If statement, caveman style.
;; The progn lets club and enjoy, both happen. Else
;; the enjoy would have been an else statement and
;; not part of the then. A "when" would probably
;; be a better way to right it.
;; This runs because non-nil is considered 't'.
;; Progn lets more than one statement be executed
;; returning the last one.

(when (caveman-horny-p seen-hottie)
  (club-back-of-head seen-hottie)
  (enjoy-the-night-with seen-hottie))
;; Using when, instead of if with progn.
;; When lets several things happen.
;; Unless is the opposite of when and would
;; let multiple elses to be evaluated.

(defmacro when2 (condition &rest body)
  `(if, condition (progn ,@body)))
;; If when did not exist, you could write it
;; like so.

(when "sick of life" "jump!")
(when t "see ya in the afterlife!")
(when nil "just-chill")
(unless t "not happening")
(unless nil "now i'll chill")

(when t
  (print "Now in a momment...")
  (print "I'm going to ask you to open your eyes")
  (print "That's right"))
;; Executes several statements

(defmacro unless2 (codition &rest body)
  `(if (not, condition) (progn ,@body)))
;; Example of how unless could be created
;; if it did not exist already.

(reverse "test")
(reverse '("test" "dog" "cat"))
;; Returns a list in reverse

(defmacro the-backwards-man (expr) (reverse expr))
(the-backwards-man ("I'm the backwards man, the backwards man. I can walk backwards fast as you can." t format))
;; Define macro backwards, that can reverse a lisp expression
;; so it is in the correct order to be evaluated,
;; as it should be (format t "blah blah")format .

(princ (reverse "!nac I ...sdrawkcab epyt nac I nam sdrawkcaB"))
;; Print string backwards

(progn (princ (reverse"مالس"))
       (terpri)
       (terpri)
       (princ "hello"))
;; If your terminal does not support bidirectional support, you could
;; reverse arabic/persian script.

(format t "Holas, I am Taizya!")
;; Three destinations to choose from:
;; t = print to terminal/console [returns nil] 
;;     t is shorthand for *standard-output*
;; nil = returns as a string [prints to console]
;; stream = output to stream

(format t "~{~a~^, ~}" '("honey" "syrup" "molasses"))
;; Return values from a list, comma delimited.
;; ~{..~} = expects a list, and loops over it

(format t "~%Holas, I am ~a" 'Taizya)
;; Prints to console, returns nil
;; ~% prints a newline

(format nil "Holas, I am ~a" 'Taizya)
(format nil "You drank ~a martinis!" 11)
(format nil "~a would you like for dinner" "Who")
(format nil "Uhm.. ~a are horrible pets!" '("cats" "dogs" "birds"))
;; Returns as a string [with nil] 
;; Removes the side effect of prining NIL after evaluation
;; ~a argument place holder replaced as string,
;; aesthetic, human readable, strings without quotes
;; keywords without the leading :
;; ~a = Human readable

(format nil "Formatted value is: ~a" 10)
(format nil "Formatted value is: ~a" "ten")
(format nil "Formatted value is: ~a" (list 7 8 9))

(format t "This sentence can be continued on ~
           this line down here, thanks to ~~")
;; Use ~ by itself to break a line while coding and ignore
;; the extra whitespace when being evaluated/returned.
;; To print a ~ in the format body use ~~

(format t "Elbow grease $~$! DJ $~$! Nook $~$! Balloon knot $~$"
                         10.25 20.5 30.75 40)

(format t "~a:~20t~a" :mykeyword "Come on in"
;; t = tabular
;; ~20t = fill spaces to start on 20th column

(format t "~$" pi)
;; ~$ = two decimal places [by default]

(format t "~4$" pi)
;; Prints out 4 decimal places.
;; Some directives take prefix parameters, like
;; this 4.

(format t "~v$" 10 pi)
;; Print out pi to the 10 decimal place.
;; v = place the prefix after the directive. 
;; In this case v will be replaced with 10.

(format t "~,11f" pi)
;; Print out pi to 11 decimal places. Using
;; the float directive this time.

(format t "~d" 999999999)
(format t "~d" -999999999)
(format t "~@d" 999999999)
;; The '@' puts a '+' in front of positive numbers

(format t "~:d" 999999999)
(format t "~:@d" 999999999)
;; : = add commas in the proper places.

(format nil "~15d" 500000)
;; Pad with spaces.

(format nil "~15,'0d" 500000)
;; Pad with 0's.

(format nil "~4,'0d-~2,'0d-~2,'0d" 2012 23 12)
;; Date formatting

(format nil "~:d" 500000000)

(format nil "~,,'.,4:d" 500000000)
;; Seperate in groups of 4 by '.'

(format t "~#$" pi)
(format t "~#$" pi pi)
(format t "~#$" 5 pi)
(format t "~#$" 3.14 pi)
;; Playing around, not sure how to use # correctly
;; but this gives an idea of what it is doing.

(format t "Error: Non acceptable character: ~:c" #\space)
(format t "~@c~%" #\x)
(format nil "~:@c" (code-char 65))
(format nil "~:@c" (code-char 13))
(format nil "~:@c" (code-char 32))
(format nil "~:@c" (code-char 127))

(format nil "~f" pi)
(format nil "~,6f" pi)
(format nil "~e" pi)
(format nil "~,6e" pi)
(format nil "~$" pi)
(format nil "~2,6$" pi)

(format nil "booger~p" 1)
(format nil "booger~p" 2)
(format nil "booger~p" 0)
(format nil "~r booger~:p" 1)
(format nil "~r booger~:p" 2)
(format nil "~r booger~:p" 0)
(format nil "~r boog~:@p" 1)
(format nil "~r boog~:@p" 2)
(format nil "~r boog~:@p" 0)
;; Plural format

(format nil "~(~a~)" "kAte Mix COOKIES")
(format nil "~@(~a~)" "kAte Mix COOKIES")
(format nil "~:(~a~)" "kAte Mix COOKIES")
(format nil "~:@(~a~)" "kAte Mix COOKIES")
;; Formatting with capitalization.

(format nil "~[영~;일~;이~;삼~;사~]" 4)
(format nil "~[영~;일~;이~;삼~;사~:;너무많이~]" 5)
;; Conditional formatting:
;; ~:; = default result [must be last]

(defparameter *list-em*
       "~#[NADA~;~a~;~a and ~a~:;~a, ~a~]~#[~; and ~a~:;, ~a, bunches-more~].")
(format nil *list-em*)
(format nil *list-em* 'kerry)
(format nil *list-em* 'kerry 'kat)
(format nil *list-em* 'kerry 'kat 'karen)
(format nil *list-em* 'kerry 'kat 'karen 'katia)

(format t "~:[Loser~;Winner~]" nil)
(format t "~:[Loser~;Winner~]" "non-nil")

(format nil "~@[x = ~a ~]~@[y = ~a ~]~@[z = ~a~]" 15 30 45)
(format nil "~@[x = ~a ~]~@[y = ~a ~]~@[z = ~a~]" 15 nil 45)
(format nil "~@[x = ~a ~]~@[y = ~a ~]~@[z = ~a~]" nil nil nil)

(format nil "~{~a, ~}" (list "hamster" "kitty" "puppy"))
(format nil "~{~a~^, ~}" (list "hamster" "kitty" "puppy"))
(format nil "~@{~a~^, ~}" "puppy" "kitty" "hamster")
(format nil "~{~a~#[~;, and ~:;, ~]~}" (list "kitty" "puppy" "hamster"))
(format nil "~{~a~#[~;, and ~:;, ~]~}" (list "rawr" "meao"))
;; ~^ = Remove the last comma

(defparameter *or-listing*
  "~{~#[neither~;~a~;~a or ~a~:;~@{~a~#[~;, or ~:;, ~]~}~]~:}")
(format nil *or-listing* '())
(format nil *or-listing* '("me" "myself"))
(format nil *or-listing* '("me" "myself" "I"))
;; Put an or in more than one item.

(format nil "~r ~:*(~d)" 100)
(format nil "I have ~r wi~:*~[ves~;fe~:;ves~]." 1)
(format nil "I have ~r wi~:*~[ves~;fe~:;ves~]." 2)
;; ~* = jump
;; ~:* = jump backwards

(format nil "~{~s~*~^ ~}" '(:x .5 :y 10))
;; Print only keys of a plist with ~*

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Format control arguments/characters [directives]
~$ = formats money, decimal two places [default]
~f = float
~d = decimal integer
~% = newline
~& = freshline
~ = ignore whitespace till next non-whitespace character
~a = print lisp object as string w/o quotes [human readable, aesthetic]
~s = print lisp object without quotes, it also 
     attempts to make output capable of being 'read' back in.
~c = character
~:c = print out nonprinting characters
~@c = print lisp literal character syntax
~:@c = ascii code
v = place the prefix after the directive. 
~| = page seperator/break, form feed [^L] for printers and [emacs ^c^l] 
# = ???? not sure yet, got some funky results with it.
~p = pluralizes words greater than 1
~r = [~radix,mincol,padchar,commachar,comma-intervalR]
     radix=base [default is base 10, decimal]
     ~r = cardinal english
     ~:r = ordinal english
     ~@r = newer style [IV IX] 
     ~:@r = older style [IIII VIIII]
~b = binary
~o = octal
~x = hex
~[ ... ~] = Conditional formatting
~{ ... ~} = Iteration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Lisp supports bases 2-36.
;; There are 26 letter in english alphabet
;; There are 10 unique numbers. (0-9)
;; 26+10 = 36 possible bases.
;; Put # before the base value, then r, then number value.
;; To use base 36:
#36rz
#36r10
;; And base 20:
#20rj
#20r10
;; Base 2, 8, 16 are binary, octal, hex and
;; can also be represented with:
#b10
#o10
#x10
;; The default base is 10. Which can be seen with:
*read-base*
;; If you are an old school mayan and the decimal
;; system is jacking you up, you could change to
;; vigesimal [base 20], by changing *read-base*.
(setf *read-base* 20)
;; Then you could use 0-k as your numbers normal
;; numbers.
;; Note: To get back to base 10 from base 20:
(setf *read-base* a)
;; As 10 = 20, in base 20. So if you said
(setf *read-base* 10) you would be resetting
;; it to base 20 again. A = 10 in base 20.

;; There are four types of floating point numbers:
;; short, single, double, long or s,f,d,l
;; Floating points are always base 10.
1.0e4  ; [e = normal, s,f,d,l can also be used]
;; Scientific notation.

#c(3 1)  ; #c to represent complex number
;; #(3    1) 
;;  (real imaginary)
(+ #c(3 2) #c(9 5))

;; Rounding can be done with:
;; floor, ceiling, truncate.

;; Modding:
;; mod, rem
;; mod similar to perl/python %
;; rem similar to c/java %

;; Increment/decrement:
;; 1+ or incf and 1- or decf
(incf n) === (setf n (1+ n)) === (setf n (+ n 1))

(format t "~10a following me" 'quit)
;; Control characters can take padding

(format t "Use ~~s to print a ~s over there" "string")
(format t "Use ~~a to print ~a no quotes [no delimiter]" "string")
(format t "Skipping 12 spaces~12@a!" "rawr!")
(format t "skipping 12 spaces on left ~12@a" "rawr!")
(format t "Padding 6 extra ~,,6a right there" "spaces")
(format t "Print 12 spaces in groups of 4 ~12,4a there" "spaces")
(format t "Pad five ~,,5,'!a" "bars")
(format t "Pad six ~,,6,'!@a left" "bars")
(format t "Hexadecimal 47806 is a ~x!" 47806)
(format t "Binary 47806 is ~b" 47806)
(format t "Decimal 47806 is ~d" 47806)
(format t "Comma'd ~:d up!" 47606)
(format t "Space ~12d it again..." 47806)
(format t "Are you sleepy ~12,'zd ?" 47806)
(format t "48706.48706 is ~8f" 47806.47806)
(format t "48706.48706 is ~,8f" 47806.47806)
(format t "~,,2f percent lisp" .47806)
(format t "Who's your char~c boiy" #\?)
(format t "Next page please ~3| Hmm.. Don't like me?")
(format t "How do you say ~r, in english?" 127)
(format t "What place did you rank? ~:r" 127)
(format t "Them young romans counted like: ~@r" 129)
(format t "Them ancient romans liked counting like: ~:@r" 129)

(defun had-secret (with-partner with-someone-else
                             &optional (tell-partner nil tell-partner-p))
  (let ((total-times (+ with-partner with-someone-else)))
    (when tell-partner-p
      (format t "~%You Choose to~
              ~:[ **to keep it a SECRET** ~; **rat yourself out!**~]"
                       tell-partner)
              (if tell-partner
                (format t "~%You hid it from me! We are DONE!!~
                        ~%At least you got to see your partner... ~:d times, before the beak up!."
                        with-partner) 
                (format t "~%You sly little devil.. You hid it ~:d times without getting caught!"
                        with-someone-else)))
              (format t "~%You hid secrets ~:d times in total!"
                      total-times)))
(had-secret 4 8)
(had-secret 4 8 1)
(had-secret 4 8 nil)
;; Tell-partner-p with :[ conditional between this ~; and this]
;; depending on what is passed in arguments. Using nil lets you
;; not tell on yourself. ~:d is decimal when using format t.

;; progn
;; Stuff extra commands in a single expression

(progn (princ "holas")
   (terpri)
   (princ "hello"))
;; 'Terpri' starts a new line

(progn (princ "안녕하세요")
   (fresh-line)
   (princ "hello"))
;; 'fresh-line' starts a newline, if cursor not at front of first line

(progn (princ "안녕하세요")
   (fresh-line)
   (fresh-line)
   (princ "hello"))
;; Two 'fresh-line's only make one new line

(progn (princ "سلام")
       (terpri)
       (terpri)
       (princ "hello"))
;; Prints two newlines

(progn (format t "~~% is equivalent to terpri ~%")
       (format t "~%yep, down here...."))
;; ~% is equal to terpri


(progn (format t "~~& is equivalent to fresh-line ~&")
       (format t "~&does not make two lines"))
;; ~& only creates one new line

(format t "Jump five lines ~5% about here")
;; Add extra lines

(defun random-programer ()
  (nth (random 7) '("asm" "ruby" "c" "python" "lisp" "tcl" "haskel")))
(random-programer)
(loop repeat 12
      do (format t "~6t~a ~18t~a ~30t~a~%"
                 (random-programer)
                 (random-programer)
                 (random-programer)))
(loop repeat 10
      do (format t "~30<~a~;~a~;~a~>~%"
                 (random-programer)
                 (random-programer)
                 (random-programer)))
(loop repeat 16 do (format t "~30:@<~a~>~%" (random-programer)))
(loop repeat 12
      do (format t "~30:@<~a~;~a~;~a~>~%"
                 (random-programer)
                 (random-programer)
                 (random-programer)))
(loop repeat 15
      do (format t "~10:@<~a~>~10:@<~a~>~10:@<~a~>~%"
                 (random-programer)
                 (random-programer)
                 (random-programer)))
;; Print out in tabular format
;; Second loop: spaces out evenly per line, [not column]
;; Third loop: print one column centered middle
;; Fourth loop: almost aligned
;; Fifth loop: all columns centered with each other evenly spaced
;; ~t = tabular

(setq do-it 0)
(loop
  (setq do-it (+ do-it +1))
  (print do-it)
  (when (> do-it 10)
    (return do-it)))

(defun random-bsds ()
  (nth (random 38) '("open-bsd" "net-bsd" "freebsd" "dragonflybsd"
                     "pc-bsd" "archbsd" "junos" "386bsd" "bsd/os"
                     "sunos-4.1.4" "ultrix"  "tru64-unix" "os-x"
                     "ios" "darwin" "ghostbsd" "desktopbsd"
                     "closedbsd" "freesbie" "picobsd" "nanobsd"
                     "anonym.os" "miros-bsd" "microbsd" "ekkobsd"
                     "4.4bsd" "dynix" "next" "nextstep" "dec"
                     "gentoobsd" "kfreebsd" "pfsense" "paxym"
                     "maheshabsd" "karmabsd" "jibbed" "midnightbsd")))
(defparameter *bsds* (loop repeat 38 collect (random-bsds)))
(format t "~{~a has bsd influence! ~}" *bsds*)
;; Print out OSes with BSD influence

(format t "|~{~<|~%|~,33:;~2d ~>~}|"
        (loop for x below 204 collect x))
;; Create chart from 0 to 203


;; when
;; Enclosed expressions are evaluated when true
 
;; unless
;; Enclosed expressions are evaluated when false
 
;; cond
;; Can handle more than one branch

(cond (1 (print "blah"))
      (2 (print "blah blah"))
      (t (print "nahnhanahanah")))
(cond (nil (print "blah"))
      (2 (print "blah blah"))
      (t (print "nahnhanahanah")))
(cond (nil (print "blah"))
      (nil (print "blah blah"))
      (t (print "nahnhanahanah")))
;; Cond can be more convienient than trying
;; to nest mulitple ifs, and branching with them.

(setq mood "happy")
(cond
  ((equal "happy" mood) "I feel great")
  ((equal "sad" mood) "This planet sucks")
  ((equal "whatever" mood) "meh"))

;; case
;; Can be used to branch on symbol values
;; ***cannot be used to branch on strings***
;; Since it is using: eq for it's comparisons
;; Case will return nil, if it has no matches.

;; ecase
;; Error case / exhaustive case
;; Signals an error the key value does not match
;; any listed keys.

(defparameter her 'interesting)
(case her
  (rude "i'd converse if i was drunk")
  (interesting "i'd talk to her")
  ((stinky dirty) "i'd speak if she showered")
  (otherwise "of course!"))

;;;;;;;;;;;;;;;;;;;;
;; Logical Functions

(not t)
(not nil)
(not '(apple candy pink))
(not (atom '(rotten pickle jam)))
;; Returns t if argument evaluates to t
;; Retruns nil if argument evaluates to any non-nil value

(or nil t)
(or t t)
(or nil nil)
(or (evenp 21) (atom '(no way)) (* 444 2))
;; Returns nil if all arguments evaluate to nil.
;; Returns the 1st non-nil value it comes across,
;; evaluating from left to right.

(and 'cat 'nail 'nip 'nil)
(and (oddp 4) t)
(and t)
(and 'mouse 'trap)
(and 'moo 'cow (- 24 2))
;; Evaluating from left to right if it comes across
;; any value that is nil, it returns nil.
;; Else it will return the last value it evaluates.

;;end-logical-functions
;;;;;;;;;;;;;;;;;;;;;;;

(and (evenp 6) (evenp 8) (evenp 4))
;; Using and conditional to check if three values are even

(or (evenp 2) (evenp 3) (evenp 5))
;; Using or to see if at least one value is even

(not nil)
(not (= 9 9))
(and (= 7 8) (= 8 8))
(or (= 7 8) (= 8 8))
;; Not is a function, "and" and "or" are macros.
;; Not inverts a boolean value.
;; And all values need to be true.
;; Or any/just one value needs to be true.

(if (member 4 '(2 3 1 4 5))
    'four-is-present
    'four-is-not-here)
;; Check to see if value is present in a list

;; find-if

;; Use eq to compare symbols [pronounced 'eek']
;; Use equal for everything else
 
;; eq
;; Used to compare symbols
 
;; eql
;; Like eq but also compares numbers and characters
 
;; equal
;; Used to compare everythig except symbols
 
;; equalp
;; Like equal, but can compare different capitalization
;; and integers with floats
;; As in (equalp 3 3.0)
 
;; =
;; For numbers
 
;; string-equal
;; For strings
 
;; char-equal
;; Compare characters, case insensitive
 
;; char=
;; Compare characters, case sensitive.
 
;; /=
;; T if all arguments have different values
 
;; These also exist:
;; <, >, <=, >=
(< 2 3 5)
(<= 5 2 3 0 1)
 
;; min
;; Pick out smallest number
 
;; max
;; Pick out highest number
 
;; zerop
;; Test for 0
 
;; minusp
;; Test for negative number
 
;; plusp
;; Test for positive number
 
;; not-greaterp
;; not-lessp

;; Character Comparison Functions
;; Numeric Analog  Case-Sensitive  Case-Insensitive
;; =               char=           char-equal
;; /=              char/=          char-not-equal
;; <               char<           char-lessp
;; >               char>           char-greaterp
;; <=              char<=          char-not-greaterp
;; >=              char>=          char-not-lessp
;; 
;; String Comparison Functions
;; =               string=           string-equal
;; /=              string/=          string-not-equal
;; <               string<           string-lessp
;; >               string>           string-greaterp
;; <=              string<=          string-not-greaterp
;; >=              string>=          string-not-lessp

(string= "polygamy" "monogamy" :start1 4 :end1 8 :start2 4 :end2 8)
;; Match a substring from two words
;; :end can be left off to match till end of string

(string/= "lisp" "lispalot")
;; Returns the index [placeholder] of the first mismatch of
;; the compared words
 
;; Higher Math Functions
;; log
;; exp
;; expt
;; sin
;; cos
;; tan
;; asin
;; acos
;; atan
;; sinh
;; cosh
;; tanh
;; asinh
;; acosh
;; atanh
 
;; alist
;; An association list, key/value pair

(assoc 'x '((x . 15) (y . 30) (z . 0)))
(assoc 'y '((x . 15) (y . 30) (z . 0)))
(assoc 'z '((x . 15) (y . 30) (z . 0)))
;; Using assoc on an alist.

(cdr (assoc 'x '((x . 15) (y . 30) (z . 0))))
;; Cdr on assoc can give value, rather than key

(assoc "joey" '(("shawn" . "arragant") ("joey" . "cute")) :test #'string=)
;; Use :test string= to find strings in alist.

(cons (cons "mikey" "funny") '(("joey" . "cute") ("shawn" . "boring")))
(acons 't 30 '((x . 0) (y . 0) (z . 0)))
;; Use cons to add to the beginning of a list.
;; Acons as well

(setf heroes (acons 'archer 'arrows '(('knight . 'sword) ('thief . 'dagger))))
;; Setf to actually change the value with acons.
;; Push can also be used

(defparameter *inventory* '(('potion . 1) ('gum . 2)))
(push (cons 'herbs '1) *inventory*)
*inventory*
;; Alists can be faster than a hash table, for small tables,
;; larger ones should use something other than alists. Alist
;; is probably best for small data tables.

;; copy-tree

;; copy-alist
;; assoc
;; assoc-if
;; assoc-if-not
;; rassoc
;; rassoc-if
;; rassoc-if-not
;; Rversions operate on cdrs, as a reverse lookup.
 
;; parilis
;; Used to build an alist out of two seperate lists.
 
;; (pairlis '(x y z) '(10 5 15))
;; Combines two lists into an alist. The pairs may
;; come out in the same order or in reverse.

(defparameter *opp* ())
*opp*
(setf (getf *opp* :x) 10)
*opp*
(setf (getf *opp* :x) 15)
*opp*
(remf *opp* :x)
*opp*
;; Add pair to a plist, change value, then delete pair

;; symbol-plist
;; setf get getf
;; remf
;; remprop

(destructuring-bind (r g b) (list 255 255 0)
    (list :r r :g g :b b))

(destructuring-bind (good bad ugly) (list "kat" "shnack" "ash")
  (list :good good :bad bad :ugly ugly))

(destructuring-bind (good bad ugly)
  (list "dog food" (list "dry cat food" "wet cat food") "goolosh"))

(destructuring-bind (boy (girl1 girl2) transgender)
  (list "mekel" (list "candace" "sarah") "ginger")
  (list :boy boy :girl1 girl1 :girl2 girl2 :transgender transgender))

(destructuring-bind (cdrom (monitor1 &optional monitor2) tower)
  (list "burner" (list "crt" "lcd") "sgi")
  (list :cdrom cdrom :monitor1 monitor1 :monitor2 monitor2 :tower tower))

(destructuring-bind (&key xaxis yaxis zaxis)
  (list :xaxis 8 :yaxis 12 :zaxis 40)
  (list :xaxis xaxis :yaxis yaxis :zaxis zaxis))

(destructuring-bind (&key x y z) (list :z 22 :y 33 :x 44)
  (list :x x :y y :z z))

(destructuring-bind (&whole whole &key x y z)
  (list :z "zz" :y "yy" :x "xx")
  (list :x x :y y :z z :whole whole))

;; '
;; There are two modes in lisp. Code mode and 'data-mode
;; ' marks data
;; 
;; `
;; quasiquoting creates chunks of data with embedded lisp code
;; , the comma unquotes to flip in and out of code mode during quasiquoting

`(6 7 (+ 8 9))
`(6 7 ,(+ 8 9))
;; Shows how the , lets code be executed when
;; quasiquoted

`(and ,(list 6 7 8))
`(and ,@(list 6 7 8))
`(and ,@(list 6 7 8) 9)
;; Show how ,@ can splice values together

;; mapcar
;; Takes a function and applies it to every member of a list

(mapcar (lambda (x)
         (+ x 3))
 '(1 2 3 4 5 6 7 8 9))
;; Adds three to each number in a list

(mapcar #'(lambda (x) (* 5 x)) (list 4 5 6))
(mapcar #'+ (list 7 8 9) (list 9 8 7))

;; mapc
;; Like mapcar but does not return the transformed list
 
;; Functions that take other functions as parameters are called:
;; higher-order functions
 
;; #'
;; Shorthand for the function operator

call-arguments-limit
;; Shows the maximum number of allowed arguemnts to a function
;; [not a modern problem]

;; Functions that return true or nil are called predicates and
;; are named with a p at the end. Such as: evenp, oddp,
;; user-created-function-p

;; push/assoc
;; To replace a value from an alist, push new items onto the
;; list. assoc will only report the most recent value

;; print
;; prints a newline before a value, and a space afterwards
 
;; prin1
;; Same as print without the newline and space
 
;; princ
;; Prints for humans
;; Cannot be read back into lisp

#\newline
#\tab
#\space

(read)
(read *standard-input*)
;; User input

read-line
;; Takes user input as a string

'|recongnizeCaseWithPipes|
;; Vertical pipes around symbol names will make them case sensitive

;; eval
;; Execute code. [ex: variable that contains code]
'(+ 1 2)
;; Will not execute but this will:
(eval '(+ 1 2))

;; #'
;; Function operator [can be used to describe a defined function]
;; 
;; lambda
;; A macro that defines and uses a function withough giving it a name
;; Anonymous functions.

((lambda (x) (+ 3 x)) 5)
;; Simple lambda function example.

(funcall #'(lambda (x) (* x x)) 9)
(funcall (lambda (x y) (+ x y)) 60 40)
((lambda (x) (* x x x)) 9)
;; Examples of using lambda

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defmacro my-let (variable-name values &body body-of-macro-code)
  `(let ((,variable-name ,values))
     ,@body-of-macro-code))

(my-let mul-add (+ 20 10)
        (* mul-add mul-add))

;; Define a macro called my-let and then use it
;; to to create mul-add
;; &body = put all remaining expressions in a nested list
;;         This lets my-let have multiple statements
;;         if needed. Like the normal let.

(my-let mul-add (+ 3 2)
        (princ "Add then multiply and print evalution:")
        (* mul-add mul-add))

(let ((mul-add (+ 20 10)))
  (* mul-add mul-add))
;; This is what the normal let would look like.
;; Notice it has more parantheses.

;; Lisp Macros let you create you own languages.
;; DSL - Domain Specific Language
 
;; Basically lisp uses macro expansion to turn
;; you macros into actual lisp code that it
;; understands, before trying to run it.
;; When you define a macro, you are teaching
;; lisp how to translate your code to lisp.
 
;; Macros are run before the program
;; [Macro Expansion Time]. A function
;; is run at runtime.
 
(macroexpand '(my-let mul-add (+ 5 8)
               (* mul-add mul-add)))
;; Macroexpand displays the raw code that is
;; generated by a macro. It will return T
;; stating that it was a valid macro and
;; could expand the code. This is useful
;; for debugging and testing macros and
;; their structure. Show lower level
;; than macroexpand-1.
 
;; Macroexpand-1
;; Takes lisp expression as argument and
;; returns the result of doing one level
;; of macro expansion. This can be better
;; for checking out your own macros than
;; macroexpand, as it won't expand other
;; macros such as do and loop.
 
;; *** Quasiquoting is used: ` , , ,@
;; ,@ = is needed to represent the body
;; 
(defun addem (x y)
  (my-let z (+ x y)
          (format t "Add em up and get ~a" z)
          z))
(addem 45 20)
;;  Create a function called addem, that adds
;; two numbers, and uses the my-let macro.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; higher-order functional programming
;; Passing functions as values

(substitute-if #\a #'digit-char-p "Joe M4mmy h9s 4 fine c9r")
;; Substitutes any digits that are found to the letter a

(subst 1 20 '(0 20 (0 20 0) ((20 20) (0 0))))
;; Subst works on cons cells. Subst works on trees, while
;; substitute works with sequences.
 
;; functions-with-not-at-end-not
;; Functions with not at end in common lisp are considered
;; deprecated and could be taken out at any time
 
;; complement 
;; Complement means opposite, can be used instead of a function with not at end.
;; Ex) Instead of: remove-if-not 
(defparameter *alphanum* '(#\! #\? #\% #\a #\b #\c #\1 #\2 #\3))
(remove-if (complement #'alphanumericp) *alphanum*)

;; nullary functions
;; Small functions that have zero arguments
 
;; thunk or suspenion
;; nullary functions that describe a computation that are to be
;; ran later

(with-open-file (my-stream
                  "test-write-file.txt"
                  :direction :output
                  :if-exists :supersede)
  (princ "Whoopie! I'm in the file now?" my-stream))
;; An example of writing text to a file

(with-open-file (stream "read-me.txt")
  (format t "~a~%" (read-line stream)))
;; Read a line from a file

(with-open-file (stream "just-created.txt" :direction :output)
  (format stream "Lisp just made me!"))
;; Create a file.

(let ((flof (open "read-me.txt")))
  (format t "~a~%" (read-line flof))
  (close flof))
;; Read the first line of a file.
;; with-open-file is safer to use and will make sure
;; the file is closed, even if error early returns.

(let ((flof (open "read-me-not.txt" :if-does-not-exist nil)))
  (when flof
    (format t "~a~%" (read-line flof))
    (close in)))
;; Display first line of a file, if it does not exist
;; return nil.

(let ((cat-file (open "read-me.txt" :if-does-not-exist nil)))
  (when cat-file
    (loop for line = (read-line cat-file nil)
          while line do (format t "~a~%" line))
    (close cat-file)))
;; Print out all lines of a file.

;; Need a file with s-expressions in it for next example.
;; Create such a file in bash called sexp-demo.txt:
;; echo -e '(4 5 6)\n789\n"string me up baby!" ;lisp comment\n((a b)\n (c d))' > sexp-demo.txt

(defparameter *sexpy* (open "sexp-demo.txt"))
(read *sexpy*)
(read *sexpy*)
(read *sexpy*)
(read *sexpy*)
(read *sexpy*)
(read *sexpy*)
(read *sexpy*)
(close *sexpy*)
;; After setting the open file to a variable, you can
;; return out each line by recalling read on the variable.
;; In this case each line is an s-expression
;; The comment does not get returned.
;; This could be used for a configuration file,
;; for instance.

;; read-byte
;; reads binary data
;; '(unsigned-byte 8)

;; read-sequence
;; read-char
;; write-char
;; write-string
;; terppi
;; fresh-line
 
;; pathnames
;; host, device, directory, name, type, version
 
;; pathname-host
;; pathname-device
;; On windows these one of these should show the
;; drive letter of the file. Irrelevant on *nix.
 
;; pathname-version
;; ??

*default-pathname-defaults*
;; Shows current/default pathname

(pathname-directory (pathname "/home/meema/old.txt"))
;; Examine the directory components of a files pathname.

(pathname-name (pathname "/home/peepa/real-old.txt"))
;; Return the name of the file, without type/extention

(pathname-type (pathname "/usr/bin/clean-diaper.txt"))
;; Returns the type/extention of the file.

(pathname "/home/homosapien/you-be.txt")
;; show pathname syntax

(namestring #p"/um/whereme/be.txt")
;; Uses a pathname designater to return a namestring

(directory-namestring #p"/some/file/here.txt")
;; Combines directory components returning
;; directory structure

(file-namestring #p"/root/lier/not-me.txt")
;; Combines name and type for filename.

(pathname-name (pathname "/home/me/.hope"))

(pathname-type (pathname "/home/me/.hope"))
;; Will retrun nil on most unix implementations

(file-namestring (pathname "/test/me/now.txt"))
;; Includes the version if the fs supports it

(make-pathname
  :directory '(:absolute "home" "mymammy")
  :name "andme"
  :type "txt")
;; Creates a pathname from the given components.
;; This way the code can work on several file
;; systems.

(make-pathname :device "c" :directory
               '(:absolute "user" "bilian") :name "pesos")
;; This would only work on some implementations of windows,
;; as the drive letter can be stored in :device or :host

(make-pathname :type "html" :defaults "holas")
(make-pathname :directory '(:relative "pickles") :defaults "bite-me.txt")
(make-pathname :type "xml" :version :newest :defaults "this-file")
;; Safer ways to create pathnames

(make-pathname :directory '(:relative "class-notes")
               :defaults #p"/myfiles/storage/math.txt")

(merge-pathnames #p"/killer/bees/yall.txt" #p"/www/beehive/sting.html")
(merge-pathnames #p"/killer/bees/" #p"www/beehive/sting.html")
(merge-pathnames #p"/killer/" #p"/www/beehive/sting.html")
(merge-pathnames #p"killer/bees/" #p"/www/beehive/sting.html")
;; Merge pathnames can overide what is not there. Can also
;; merge relative and absolute paths.

(enough-namestring #p"/xml_pub/rsite/rawr.xml" #p"/xml/")
;; Get a relative path.

(merge-pathnames
  (enough-namestring #p"/home/users/julio/.vimrc" #p"/home/")
  #p"/config-bkup/")
;; Change root directory creating a path.

(make-pathname :name "tester" :type "rb")

(merge-pathnames #p"suzie.gif")
;; This will fill in the rest of the path with
;; whatever: *default-pathname-defaults*
;; is set to.

(make-pathname :directory '(:absolute "gogo") :name "dancer")
(make-pathname :directory '(:absolute "gogo" "dancer"))
;; Create directory paths
;; The second example returns with an ending: /

;; probe-file
;; rename-file
;; delete-file
;; ensure-directories-exist
;; file-write-date
;; file-author
;; file-length
;; file-position

(file-write-date "read-me.txt")
;; Shows seconds from 01.01.1900 gmt

(file-author "read-me.txt")
;; Show owner of file

(with-open-file (in "read-me.txt" :element-type '(unsigned-byte 8))
  (file-length in))
;; Safer to use than file-length. This returns bytes, where file-length
;; can chande per implementation.

;; Two Other ways to get file size:

(with-open-file (inside "read-me.txt")
  (loop while (read-char inside nil) count t))

(with-open-file (in "read-me.txt")
  (let ((scratch (make-string 4096)))
    (loop for read = (read-sequence scratch in)
          while (plusp read) sum read)))

(let ((s (make-string-input-stream "2.45")))
  (unwind-protect (read s)
    (close s)))
;; Convert string to float

;; Also like this:
(with-input-from-string (s "2.45")
  (read s))

(with-output-to-string (boom)
  (format boom "pshhhfffa ")
  (format boom "~s" (list 4 5 6)))
;; Create a new string

*features*
;; Displays a list of features under the current
;; implementation. [It is a list of symbols]

(defun which-implementation ()
  #+sbcl (print "haha! I am sbcl")
  #+clisp (print "hmm. You can call me clisp")
  #-(or sbcl clisp) (error "Figure out which lisp, yourself!"))
;; Will run code depending on which implenattion
;; of lisp, the code is running under.
;; Some others are: allegro cmu

(directory (make-pathname :name :wild :defaults "~/"))
;; Get a list of files in the current user's home directory

(defparameter *movie-set* ())
(adjoin "lights" *movie-set*)
*movie-set*
(setf *movie-set* (adjoin "lights" *movie-set*))
*movie-set*
(pushnew "camera" *movie-set* :test #'equal)
(pushnew "camera" *movie-set* :test #'equal)
*movie-set*

(subsetp '(5 6 7) '(4 5 6 7))
(subsetp '(5 6 7) '(8 9 10))
;; Checks to see if first sequence is a sub set of
;; the second. Returns: t or nil

(defvar *chosen-directory*)
(defvar *chosen-file*)
(defun import-file (file directory)
  (let ((*chosen-directory* directory)
        (*chosen-file* file))
    (print *chosen-directory*)
    (print *chosen-file*)
    (load-this)))
(defun load-this ()
  (load (merge-pathnames *chosen-directory* *chosen-file*)))
;; This is a long and drawn out waty to load file and can be
;; called like this:
(import-file "~/nixfilepath/testing/" access-me-lisp.txt")
(import-file "c:\\winfilepath\\testing\\" "access-me-lisp.txt")

:before-a-symbol
;; Is a keyword symbol (a constant). Any symbol that starts with a ':'
;; is a keyword. Keywords evaluate to themselves.

(loop for cons on '("gumbo" "jambalaya" "boudin")
      do (format t "~a" (car cons))
      when (cdr cons) do (format t ", "))
;; Print out values in a list, comma delimited.

(loop repeat 8
      collect 2)
;; collect 8 2s (prints eight2s) 

(loop for n from 1 to 10
      collect n)
;; Count to 10

;; let
;; Can not refer to another defined variable

(let ((x 2))
  (+ x (let ((x 20))
         (+ x 2))))
;; Not a smart way to use let, but lisp e'll let you. 2+20+2=24
;; Inner binding shadows the outer, if two variables are named
;; the same.

;; let*
;; Can refer to another defined variable
;; You can just use let* unless there is a reason to use let.

(let* ((x "Taizya")
       (y x))
  (print "My ex-girlfriend is")
  (princ x)
  (print "My girlfriend is")
  (princ y))
;; Let* lets y = x. Let will not let you do this. As it can
;; not refer to another variable in the scope. Let will not
;; let you have girlfriend y who is your ex-girlfriend x.
;; Let* lets you have as many ex-girlfriends as you want
;; to be your girlfriend.
;; Also my girlfriends are local x y [they are using let]. No
;; other parts of the program can see them, unless I let them
;; be coded in here with my girlfriends, and that is not
;; gonna happen, at least not in this example.

(let* ((me "joe")
       (myme (concatenate 'string me "mammy")))
  (list me myme))
;; Let* let's myme use me.
;; A simpler example below.

(let* ((x 50)
       (y (+ x 30)))
  (list x y))
;; Let* lets y use x in it's definition. Let will not.
;; Although you could just use two lets, as below.

(let ((me "joe"))
  (let ((myme (concatenate 'string me "mammy")))
    (list me myme)))
;; Using two lets to accomplish what let* would do.

(let ((x 50))
  (let ((y (+ x 30)))
    (list x y)))
;; Using two lets to accomplish what let* would do.
;; Same as above.

(make-array 4)
;; Create an array of size 4

(make-array 6 :initial-element nil)
;; Create a single dimensional array [vector]
;; with 6 elements all initialized to nil.

(defparameter *z* (make-array 6 :initial-element nil :fill-pointer 0))
;;
(vector-push 'c *z*)
;; Push an element onto a vector
;; Can be used on arrays that have a fill-pointer.
;;
(vector-pop *z*)
;; Pop the last element off a vector.
;;
(make-array 6 :fill-pointer 0 :adjustable t)
;; Create an adjustable vector. Which can
;; hold more than 6 elements.
;;
;; adjust-array
;; Can also be used to modify arrays.
;;
(vector-push-extend 'g *z*)
;; Lets you extend an adjustable vector/array and
;; add an element even if it is full.
;; ...-extend is used for arrays that have a fill-pointer
;; and are adjustable.

(make-array 5 :fill-pointer 0 :adjustable t :element-type 'character)
;; Create an adjustable string vector. Strings such as "this one"
;; are usually fixed.

(defparameter kitten (make-array) 3))
(setf (aref kitten 1) 'crazy)
;; Sets the 2nd value in the kitten array to 'crazy
(aref kitten 1)
;; Return the 2nd value of the array kitten

(defparameter *y* (vector 4 5 6))
(length *y*)
(elt *y* 0)
(elt *y* 1)
(elt *y* 2)
(setf (elt *y* 0) 11)
*y*
;; Create vector *y* as (4 5 6)
;; Then use 'elt' to to view each element
;; Set the 0 index of *y* to 11
;; Now you can view *y* as: (11 2 3)

;; Simple Sequence Functions
;; Name         Required Arguments         Returns
;; count        Item and sequence          # of times item appears
;; find         Item and sequence          Item or nil
;; position     Item and sequence          Index into sequence or nil
;; remove       Item and sequence          Sequence with item removed
;; substitute   New item, item, sequence   Sequence with item replaced   

(count 'friend '(friend enemy stranger friend))
(count 4 #(2 3 4 5 6 5 4 3 2 3 2 1 0))
(find 6 #(1 2 3 4 5 6 7 6))
(find 'me '(him her you them me))
(find 100 #(1 2 3 4))
(position 14 #(12 13 14 15))
(position 'yep '(yes no hrm yep))
(remove 1 '(1 1 1 2 1 3 1 4 1))
(remove 'bad '(good bad ugly))
(substitute 0 2 #(1 2 1 2 1 2 1 2))
(substitute 'me 'team '(there is no you in team))

(count 10 '(10 2 1) :test #'equalp)
;; Test to see if 10 is in sequence

(count 10 #(10 2 1) :test (complement #'equalp))
;; Returns how many items are not 10

(count 10 #(10 2 1) :test-not #'equalp)
;; Returns how many items are not 10
;; *** This is deprecated and complement should
;;     be used instead. [like above]
;;
(count 10 #(10 2 1 10 2 1 2 3 4 5 6 7 8 9 0 10))
;; Counts 10s

(count 'kat '(kitty kitty bang bang kat) :test (complement #'equalp))
;; Returns how many items are not: kat

(count "kat" #("kat" "is" "hot") :test #'string=)
(count "kat" #("kat" "is" "a" "hot" "kat") :test #'string=)
;; Count how many strings are: "kat"

(find 'q #((o 15) (p 16) (q 17)) :key #'first)
;; Find item with q in the first position 

(find 'q #((o 15) (p 16) (44 q)) :key #'second)
;; Find item with q in second position

(find 'z #((z 5) (w 23) (z 42) (b 69)) :key #'first :from-end t)
;; Find item with z in first posistion starting from the end.

(find 'z #((z 1) (z 2) (z 3)) :key #'first :start 1)
;; Start from the index 1 instead of 0.

(find 'z #((z 1) (z 2) (z 3)) :key #'first :start 1 :end 3)
;; :end could also be added to search a subsequence.

(remove #\a "abracadabra")
;; Remove all 'a's

(remove #\a "abracadabra" :count 3)
;; Remove the first three 'a's

(remove #\a "abracadabra" :count 3 :from-end t)
;; Remove the last 3 'a's

(defparameter *r* #((p 0) (o 9) (n 0x)))
(defun verbose-first (c) (format t "Crack how? ~s~%" c) (first c))
(count 'n *r* :key #'verbose-first)
(count 'n *r* :key #'verbose-first :from-end t)

;; Standard Sequence Function Keyword Arguments
;; Argument     Meaning                   Default
;; :test        2 arguments item or       eql
;;              :key to element
;; :key         1 argument extracts
;;              key value from element    nil
;;              nil means leave as is
;; :start       Starting index of         0
;;              subsequence
;; :end         Ending index, nil
;;              states end of sequence    nil
;; :from-end    If true reverses order,  
;;              end to start
;; 
;; :count       Number of elements to    nil
;;              remove or substitute,
;;              nil to affect all for
;;              remove and substitute

(count-if #'oddp #(3 4 5 6 7))
(count-if-not #'oddp #(3 4 5 6 7))
;; Count odd and not odd numbers in sequence

(position-if #'digit-char-p "d0n0ut2")
;; Show position of the first number if there is one

(remove-if-not #'(lambda (y) (char= (elt y 0) #\k))
            #("kat" "jack" "john" "miriam"))
;; Go through sequence and remove all elements
;; not starting with a 'k'

(count-if #'oddp #((4 h) (3 d) (2 c) (1 z)) :key #'first)
(count-if-not #'oddp #((4 h) (3 d) (1 z)) :key #'first)

(remove-if-not #'alpha-char-p #("123" "3y3z" "hi" "there")
            :key #'(lambda (y) (elt y 0)))
;; Remove any element that is not pure alphabet characters

(remove-duplicates #(1 0 2 0 1 3 0 0 1 4 0))
;; Remove any duplicates in the sequence, leaving
;; just one of each

(copy-seq #(1 2 3))
;; Makes a new copy of the sequence, of the same type

(reverse #(5 4 3 2 1))
;; Reverses the sequence by making a new one
;; of the same type

(concatenate 'vector #(2 4 6) '(3 5 7))
;; Concatenates and returns a vector

(concatenate 'list #(2 3 4) '(5 6 7))
;; Concatenates and returns a list

(concatenate 'string "You talking to " '(#\m #\e #\?))
;; Concatenate and return a string

(sort (vector "lisp" "is" "horrible") #'string<)
;; Sort sequence as string alphabetically
;; There is also: sort-stable which will not
;; reorder equivalent elements. Sort is destructive
;; so you should pass it to another function or
;; assign it to a variable, like so:
(setf wrong-order '(2 4 5 3 1))
(setf wrong-order (sort wrong-order #'<))

(merge 'vector #(9 7 5) #(10 8 6) #'>)
(merge 'vector #(9 7 5) #(10 8 6) #'<)
;; Merges the to sequences into one. If
;; they are in a correct sort order already
;; they will get sorted when combined, else
;; it will just merge them without them
;; being sorted.

(subseq "hey come here now!" 4)
;; Pulls out a subsequence of a sequence,
;; from a determined starting point

(subseq "hey come here now!" 4 17)
;; Pulls out a subsequence of a sequence,
;; from a determined starting point till
;; a chosen ending point.
 
(defparameter *m* (copy-seq "mammamia"))
(setf (subseq *m* 2 5) "rru")
;; Define *m* then change it with setf and
;; a subsequence. If the subseq and the
;; sequence are not the same length, the
;; shorter will override, ommitting the rest.
;; Examples below:

(setf (subseq *m* 5 8) "eeee")
;; The are too many 'e's so the last is
;; dropped off. 5-8 only allows for 3.

(setf (subseq *m* 5 8) "e")
;; There are not enough 'e's to fill
;; 5-8 so only one character will be
;; replaced.

(search "kat" "ekatylin")
;; Search for the starting point of subseq
;; in a sequence. Similar to position, but
;; can find a sequence rather than just a
;; single character.

(mismatch "katy" "kathleen")
;; Returns the index [place] where the two
;; sequences diverge. Will retrun nil if
;; they both match.
;; :key, :test, :start1, end1, :start2,
;; end2, from-end will also work here.

(mismatch "confusing" "tripping" :from-end t)
(mismatch "homer" "gomer" :from-end t)
;; This one is tricky:
;; It returns the index of the FIRST sequence [confusing]
;; where the similarities begin, in the first case that
;; happens to be the 'i' of confusing.
;; In the second it is the 'o' in homer.

(every #'oddp #(3 4 5 6 7))
;; Returns nil if all are not odd

(every #'oddp #(3 5 7 9))
;; Returns True 't' if all are odd

(some #'oddp #(3 4 5 6 7))
;; Returns t if some are odd

(some #'oddp #(2 4 6 8))
;; Returns nil if none are odd

(notany #'oddp #(1 3 6 9))
;; Returns nil if any are odd

(notany #'oddp #(2 4 6 8))
;; Returns true if none are odd

(notevery #'oddp #(3 4 5 6 7 8))
;; Returns true if every one is not odd

(notevery #'oddp #(3 7 9))
;; Returns nil as soon as it sees the
;; first odd number.

(every #'< #(2 4 6 8) #(3 5 7 9))
;; Compares each element of the first
;; sequence to the second to see if
;; it is less, if so it returns true

(every #'< #(5 6 7 8) #(1 2 3 4))
;; Same as above, but this would return nil

(some #'< #(7 8 9 10) #(4 5 11 8))
;; Returns true since 9 is less than 8

(some #'< #(7 8 9 10) #(5 6 7 8))
;; Returns nil since none of the elements
;; in the first sequence are less than
;; the matching elements in the second
;; sequence

(notany #'< #(4 5 6 7) #(2 3 4 9))
;; Not any of these are less than any of these.
;; Returns nil in this case because 7 is less
;; than 9

(notany #'< #(6 7 8 9) #(5 6 7 8))
;; Returns true since not any of the first
;; sequence are less than the matching
;; element in the second one.

(notevery #'< #(1 2 3 4) #(0 1 2 3))
;; Returns true becuase not all elements
;; in first sequence are less than the
;; matching element in the second.

(notevery #'< #(1 2 3 4) #(2 3 4 5))
;; Returns nil

(map 'vector #'* #(1 2 3 4 5) #(1 2 3 4 5))
;; This map multiplies each element in the
;; first sequence with the matching in the
;; second. 'vector tells it what kind of
;; sequence to create.

(setq c (list 2 4 6 8) d (list 1 3 5 7))
(map-into c #'+ c d)
;; Map-into creates a new sequence, in this
;; case by adding 'c' and 'd' and stuffing
;; them in 'c'.

(setq ages (list nil nil nil))
(setq born (list 1923 1965 1977) death (list 1975 1990 2012))
(map-into ages #'- death born)

(setf germ '("nasty" "nappy" "no"))
(second germ)
(setf (second germ) "ooooooOH")
germ
;; Set a list then change the second value of the list

(round 3.2)
;; Return rounded number and then return the remainder

(defstruct are-you-my-mommie
           name
           birthday 
           measurements
           height
           weight
           sign)
;; Define a Structure. Structures are useful for any data
;; that will change over time. (ex: like age)


(defparameter *nyomi-marcela* (make-are-you-my-mommie
                                :name "Nyomi Marcela"
                                :birthday "June 22, 1980"
                                :measurements "34B-22-33"
                                :height "162 cm"
                                :weight "106 lbs"
                                :sign "Cancer"))
;; Create instance of a structure

(are-you-my-mommie-sign *nyomi-marcela*)
(setf (are-you-my-mommie-weight *nyomi-marcela*) "105 lbs")

(defparameter *ask-her* #S(ARE-YOU-MY-MOMMIE
                            :NAME "Nyomi Marcela"
                            :BIRTHDAY "June 22, 1980"
                            :MEASUREMENTS "34B-22-33"
                            :HEIGHT "162 cm"
                            :WEIGHT "106 lbs"
                            :SIGN "Cancer"))
;; Structures are good to store data that is going to mutate


(length '(x y z))
(length "kat")
(length (make-array 9))
;; Get the length of a string, array, and list

(find-if #'numberp '(x y z 3 2 1))
;; Find first value that satisfies a predicate (ex: numberp)

(count #\t "ribbitribbit")
;; Count occurences

(position #\b "treebug")
;; Shows location

(some #'numberp '(q r s 6 5 4))
;; Do some of the values match a predicate

(every #'numberp '(1 2 3 4 5))
;; Does every value match predicate

(reduce #'+ '(23 5 69 42 13))
;; Reduce sequence to a single result by iterating through it
;; Reduce can use keywords such as:
;; :initial-value , :key, :from-end, :start, :end

(reduce (lambda (highest num)
          (if (and (oddp num) (> num highest))
            num
            highest))
        '(1 2 3 4 5 6 7 8 9 10)
        :initial-value 0)
;; Use reduce to find highest odd number

(reduce #'max #(22 1 20 10))
;; Find max value

(map 'list
     (lambda (x)
       (if (eq x #\b)
         (char-upcase x)
         x))
     "All your base are belong to us!")
;; Use map to go through string converting it to a list
;; of characters and changing all letter b's to uppercase

(map 'string
     (lambda (x)
       (if (eq x #\b)
         (char-upcase x)
         x))
     "All your base are belong to us!")
;; Same as above, except returns a string

(subseq "lemondrop"  3 8)
;; Pulls out a sequence from start to end values

(sort "x9!3?b%w6_h+2" #'char-lessp)
;; Sort string by lowest value

(sort '(9 2 4 6 32 23) #'>)
;; Sort using greater than function

(numberp 23)
;; Check to see if value is a number
;; A few others are: arrayp, characterp, consp, functionp,
;; hash-table-p, lisp, stringp, symbolp (these are type-predicates)

(defun add (a b)
  (let ((x (+ a b)))
    (format t "The sum is ~a" x)
    x))
(add 20 33)
;; Create a function to add two numbers

(defun addnls (x y)
  (cond ((and (numberp x) (numberp y)) (+ x y))
        ((and (listp x) (listp y)) (append x y))
        ((and (stringp x) (stringp y)) (concatenate 'string x y))))
;; Create function addnls that takes two arguments and checks if they
;; are numbers, if so adds them. If lists it appends them. If strings
;; it concatenates them. Using defmethod would be a better way to write this.


(defmethod add-td ((x number) (y number))
  (+ x y))
(defmethod add-td ((x list) (y list))
  (append x y))
(defmethod add-td ((x string) (y string))
  (concatenate 'string x y))
;; Defmethod allows the compiler to see the type of the arguments.
;; It is used to define multiple versions of a function to be used
;; on different types [type dispatching, based on arguement types].

(defparameter *closure*
  (let ((rawr 0))
    #'(lambda () (setf rawr (1+ rawr)))))
(funcall *closure*)
(funcall *closure*)
(funcall *closure*)
;; An example of a closure changing the value of rawr

(tagbody
  top
  (print 'meow)
  (when (plusp (random 10)) (go top)))
;; Using tagbody to loop.

(dotimes (i 4)
  (princ "Wait! Come back <-")
  (fresh-line))
;; Loop that prints four times

(dotimes (dice 20)
  (let ((roll (random 40)))
    (print roll)
    (if (> roll 20) (return))))

(dotimes (i 5) (print "High five") (princ i))

(dotimes (i 12)
  (princ (random 5))
  (princ " "))
;; Print out 12 random numbers between 0 and 5

(dotimes (x 21) (format t "~d " x))
;; Count from 0 to 20

(dotimes (x 12)
  (dotimes (y 12)
    (format t "~d x ~d = " (1+ x) (1+ y))
    (format t "~d " (* (1+ x) (1+ y))))
  (format t "~%"))
;; Multiplication table 1-12

(dotimes (x 20)
  (dotimes (y 20)
    (format t "~3d " (* (1+ x) (1+ y))))
  (format t "~%"))
;; Products of multiplication tables 1-20

(defun count-upto (max)
  (let ((result nil))
    (dotimes (i max)
      (push i result))
    (nreverse result)))
(count-upto 20)
;; Count up to 20

(defun count-upto (max)
  (loop for i below max collect i))
(count-upto 20)
;; Count up to 20

(dolist (kitty-goes '("meow" "mew-mew" "mao" "rawr"))
  (print kitty-goes))
;; Loop across list items.

(dolist (kitty-goes '("meow" "mew-mew" "mao" "rawr"))
  (print kitty-goes)
  (if (equal kitty-goes "mao") (return)))
;; Break out of a do list with return

;; Dotimes and dolist are simple and use only
;; one loop variable. "Do" is more powerful/general
;; can bind as many variables as you want, and gives
;; complete control over how you can step through them.

(dotimes (x 30)
  (do ((n 0 (1+ n))
       (cur 0 next)
       (next 1 (+ cur next)))
    ((= x n) (print cur))))
;; Prints the first 30 fibonacci numbers

;; Do

(do ((i 0 (1+ i)))
  ((>= i 10))
  (print "which number?")
  (princ i))
;; Print with do.

(do ((i 5 (1- i)))
  ((> (get-universal-time) (+ (get-universal-time) i)))
  (format t "Exiting in: ~d~%" i)
  (sleep 1))
;; Do count down from 5.

(do ((num nil) (i 1 (1+ i)))
  ((> i 10) (nreverse num))
  (push i num))
;; Count to 10

(do ((x 1 (+ x 1))
     (y 1 (* y 2)))
  ((> x 5) y)
  (print y)
  (print "getting closer to the end"))

(loop for count-up from 1 to 20 collecting count-up)
;; Count to 10 by looping and collecting the numbers.

(loop for sums from 1 to 10 summing (expt sums 2))
;; Square the first 20 numbers and add them up.

(loop for vowels across "All your base are belong to us!"
      counting (find vowels "aeiou"))
;; Use loop to count vowels in a sentence.

;; decf
;; Variant of setf that subtracts from a variable

(type-of 'pickles)
(type-of 10)
(type-of "nada lada")
;; Type-of finds the type of a value

(time (dotimes (i 100) (princ "test:") (princ i) (princ " ")))
;; The time command can be used for timing your code

(loop for i
      below 10
      sum i)
;; Example using loop macro

(loop for i
      from 10
      to 20
      sum i)
;; Loop with 'from' to 'to'

(loop for i
      in '(10 20 30 40 50 60 70 80 90 100)
      sum i)
;; Loop using 'in' to iterate through a list

(loop for i
      below 30
      do (princ i))
;; Example of do'ing' something in a loop

(loop for i
      below 31
      when (evenp i)
      sum i)
;; Only do stuff 'when' it meets a certain criteria
;; In this case: 'when' it is even

(loop for i
      from 10
      to 2000
      do (print i)
      when (= i 15)
      return 'CrazyCodeStopNow!)
;; Break out of loop with 'return' 'when'

(loop for i
      in '(1 3 5 7 9)
      collect (* i i))
;; 'Collect' values into a list

(loop for x below 12
      for y below 12
      collect x
      collect y)
;; Mulitple 'for's in one loop and incrementing there values
;; at the same time. [They do not loop independently, lowest
;; value exits the loop]
 
(loop for x below 12
      for y below 12
      collect (* x y))
;; Same as above except mulitpling the collected values

(loop for x from 1 to 12
      collect (loop for y from 1 to 12
                    collect (* x y)))
;; Nested loop going through multiplication table products 1-12

(loop for i
      from 1
      for month
      in '(jan feb mar apr may jun jul aug sep oct nov dec)
      collect (cons i month))
;; Collect months and their number value in a dotted-list

(loop repeat 8
      do (print "Could you repeat that?"))
;; Repeat loop

(loop initially
      (print "Wait! I don't even know your name yet...")
      for x below 6
      do (print "Say my name %!+(&"))
;; Give an initial duty before looping through the rest

(loop for x below 4
      do (print "Oh... Don't stop!")
      finally
      (print "What! You are finished!"))
;; Give a final expression after you do the dues

(loop initially
      (print "If I had a nickel for...")
      for x below 7
      do (print "Cha ching")
      finally
      (print "I'm rich!"))
;; Initially and finally in same loop

(loop named first-loop
      for i from 1 to 3
      do (print i)
      do (princ "first loop")
      (loop named second-loop
            for j from 1 to 3
            do (print j)
            do (princ "second loop")
            when (= j 2)
            do (return-from second-loop 'exited-second-loop)))
;; Loops can be 'named' and then broken out of with 'return-from'.
;; In this case the second-loop never gets to print out it's third line.
;; Although it is broken out of, it never prints 'exited-second-loop
;; for some reason. Maybe cause the 'first-loop' keeps going and
;; keeps calling the second-loop again.

(loop named first-loop
      for i from 1 to 3
      do (print i)
      do (princ "first loop")
      (loop named second-loop
            for j from 1 to 3
            do (print j)
            do (princ "second loop")
            when (= i 2)
            do (return-from first-loop 'exited-first-loop)))
;; Exits from the first loop returning EXITED-FIRST-LOOP

(loop for i in '(1 3 5 7 9 10 12 13 15 17)
      while (oddp i)
      do (print "Yep! I'm still an odd ball: ")
      do (princ i))
;; This loop will run as long as it comes across an odd number

(loop for i
      from 0
      do (print "I'm not high enough yet: ")
      do (princ i)
      until (> i 9))
;; 'Until' this loop has i greater than 9, keep going

(loop with x = (* 2 2)
      repeat 6 
      do (print x))
;; Example of using 'with' to set an auxiliary variable in a loop

(defparameter cookie-jar (make-hash-table))
(setf (gethash 'oreo cookie-jar) "yucky")
(setf (gethash 'chocolate-chip cookie-jar) "yummy")
(setf (gethash 'oatmeal cookie-jar) "ugh")
(loop for person being each hash-key of cookie-jar
      using (hash-value tasted)
      do (print (cons person tasted)))
;; Loop through hash table with 'being' , 'each', 'using'
;; When using 'each' 'hash-key' is singular

(defparameter tv-shows (make-hash-table))
(setf (gethash 'Breaking-Bad tv-shows) 10)
(setf (gethash 'Mr-Inbetween tv-shows) 10)
(setf (gethash 'Arrow tv-shows) 5)
(setf (gethash 'Hell-on-Wheels tv-shows) 7)
(setf (gethash 'The-Walking-Dead tv-shows) 7)
(loop for series being the hash-keys of tv-shows
      do (print series))
(loop for rating being the hash-values of tv-shows
      do (print rating))
;; Loop through hash table with 'being' 'the'
;; When using 'the' 'hash-keys' is plural

(loop for i from 0
      do (print i)
      when (= i 5)
      return 'yippy!)

(loop as x from 2 to 10
      collect x)
;; Collects x into a list

(loop for i
      in '(200 125 75)
      sum i)
;; Sums the numbers in the list

(loop for x
      on '(10 20 30)
      do (print x))

(loop for i from 2 to 18
      by 2
      do (print i)
      sum i)
;; Count by 2 and sum them

(loop repeat 6
      for x = 18.0
      then (/ x 2)
      collect x)

(loop for i
      upfrom 4 to 12
      do (print i)
      sum i)

(loop for i from 4
      upto 12
      sum i)

(loop for i
      downfrom 10 to 0
      do (print i))

(loop for i from 10
      downto 3
      do (print i))

(loop for i
      across #(20 40 60)
      sum i)
;; Loop 'across' an array

(loop for i
      in '(4 12 77 1 -23)
      minimize i into lowest
      maximize i into biggest
      finally (return (cons lowest biggest)))
;; 'Into' lets variable be created, that can be returned 

(loop for i below 12
      unless (oddp i)
      do (print i))
;; Print out even numbers using 'unless'

(loop for i below 15
      if (oddp i) do (print i))
;; Print out odd numbers below 15 with 'if'

(loop for i below 15
      when (oddp i) do (print i)
      when (evenp i) do (print "me not odd"))
;; 'When' odd print number, when even print me not odd

(loop for i below 12
      sum i)
;; Sum the numbers below 12

(loop for i
      in '(5 6 7 2 3 4 8 9)
      minimize i)
;; Set i to the lowest number in list

(loop for i
      in '(99 77 23 32 0 55)
      maximize i)
;; Set i to max number in list

(loop for i
      in '(4 6 8 10 12 14)
      always (evenp i))
;; Check if all items in list are 'always' even

(loop for i
      in '(4 6 8 10 12 14)
      never (oddp i))
;; Make sure items in list are 'never' odd

(loop for i
      in '(53 2324 4737 23723 324)
      thereis (oddp i))
;; Check to see if 'thereis' and odd number

(loop for x below 6
      when (= x 4) do (print "i am four")
      and do (print "I like fours!")
      do (print "I wish I was always a four"))
;; Loop with 'and'

(loop for i below 10
      if (oddp i) do (print i)
      else do (print "I'm even yo..."))
;; Loop with an 'else'

(loop for i below 8
      when (oddp i) do (print i)
      end
      do (print "yo you!"))
;; Use 'end' to denote to stop when clause

(loop for i below 12
      append (list 'y i))
;; 'Append' to list inside loop

(loop for i below 12
      nconc (list 'y i))
;; 'Nconc' a list inside a loop

;; ***iterate a library that some prefer as it is more
;; lispy than loop. See how the loops above look
;; like they should have more parens?

(resolve-host-ipaddr "www.heebeejeebeeweeneee.com")
(resolve-host-ipaddr "8.8.178.110") 
;; Returns :name :aliases :addr-list :addr-type
;; This may only be in some lisp implementations,
;; It was working in clisp under cygwin, but not
;; sbcl under windows.

(write-to-string 127 :base 16)
(format t "~X" 127)
(format nil "~x" 127)
;; Convert the decimal 127 to hexidecimal
;; The 2nd uses format

#xf
;; Hexadecimal 15. Just like you can type
;; 15 at the repl and 15 will be printed
;; back, you can type #f and 15 will be
;; printed back. (hexadecimal numeric literal)

(format t "0x~2,'0x" 10)
;; Decimal to hex outputting 0x in front of number
;; and padding to two charcters.

(format t "0x~(~2,'0x~)" 127)
;; Decimal to hex, force hex output to be lowercase
;; with ~(

(format t "0x~{~2,'0x~^~}" (list 127 0 0 1))
(format t "0x~{~2,'0x~^~}" '(127 0 0 1))
;; Takes a list of ip quadrants and turns them to
;; there hex value

(format t "http://0x~{~2,'0x~^~}" '(127 0 0 1))
;; Spits out an ip in hex form, that can be used
;; in a browser's url bar.

(defun dec-to-bin (x &optional (callback #'princ))
  (unless (= x 0)
    (dec-to-bin (floor x 2) callback)
    (funcall callback (mod x 2))))
(dec-to-bin 900)
;; Decimal to binary

(defun dec-to-oct (x &optional (callback #'princ))
  (unless (= x 0)
    (dec-to-oct (floor x 8) callback)
    (funcall callback (mod x 8))))
(dec-to-oct 900)
;; Decimal to octal

(output-stream-p *standard-output*)
;; Check to see if standard output is a valid stream for lisp

(input-stream-p *standard-input*)
;; Check to see if standard input is a valid stream

(write-char #\z *standard-output*)
;; Write a char to chosen output stream

(read-char *standard-input*)
;; read first char from repl

(print 'Yabba-dabba *standard-output*)
;; You can explicitly tell print to send to std-out

(with-open-file (whos-stream "write-test.txt" :direction :output)
 (print "who data dis be?" whos-stream))
;; Write to file with a file output stream, and print to that stream.

(with-open-file (whos-stream "write-test.txt" :direction :input)
 (read whos-stream))
;; Read file with input stream
;; 'With-open-file' is a high level way of working with files in which
;; you do not have to worry about closing the files or corrupting them.

(let ((desired-figure '((bust . 34)
                        (waist . 24)
                        (hips . 36))))
  (with-open-file (my-stream "write-test.txt" :direction :output)
    (print desired-figure my-stream)))
;; Write a cons list to a file. [alist / association list /cons list]

(with-open-file (my-stream "write-test.txt" :direction :input)
  (read my-stream))
;; Read from file

(with-open-file (yo-stream "write-test.txt" :direction :output :if-exists :error)
  (print "nada wanna" yo-stream))
;; Try to write a file, if it already exists, error out

(with-open-file (pee-stream "write-test.txt" :direction :output
                                             :if-exists :supersede)
  (print "I am the over writer" pee-stream))
;; Explicilty tell it to overwrite file, if it already exists.

(defparameter peeing-in-a-stream (make-string-output-stream))
(princ "You can pee into a string-stream. " peeing-in-a-stream)
(princ "So can your buddies! " peeing-in-a-stream)
(get-output-stream-string peeing-in-a-stream)
;; Create a string stream. Print to it twice. Then
;; output what was written to it.

(with-output-to-string (*standard-output*)
  (princ "A large pizza has 8 slices. ")
  (princ "Eat 2 slices, and you will have ")
  (princ (- 8 2))
  (princ " slices left"))
;; Using 'with-output-to-string' macro to capture text and
;; redirect it to a string stream, and then print everthing.
;; Can be more efficient then using concatenation. This
;; breaks functional programming style, although it can
;; be useful for debugging.

(defparameter *call-me-baby* (lambda ()
                               "ok"))
(funcall *call-me-baby*)
;; Closure example

(defparameter *call-me-baby* (let ((x "oh daddy..."))
                               (lambda ()
                                 x)))
(funcall *call-me-baby*)
;; Closure example

(let ((line-number 0))
  (defun print-slave (x)
    (print line-number)
    (print x)
    (incf line-number)
    nil))
;; Use closure to keep up with a letted line-number
;; to know what line number it is on even though
;; no longer in the let.

;; Memoization remembers previosly called arguments
;; and their result. Only works on functional style
;; code

(get-universal-time)
;; Show seconds since 1900, determined by system time.

(/ (get-universal-time) 365.0 24 60 60)
;; Show how many years since 1900 till now

(get-decoded-time)
;; Breaks down time as:
;; second, minute, hour, date, month, year, day, daylight-p, zone
;; The last three are:
;; day = weekday [0 = sunday]
;; daylight-p = daylight savings true/false
;; zone = timezone [6 = central/cdt]

(defun unit-test-mult ()
  (and
    (= (* -3 4) -12)
    (= (* 2 4 6) 48)
    (= (* -8 -8) 64)))
;; Function that acts as a simple unit test.
;; Returns T if all tests pass, else
;; returns NIL.

;;;;;;;;;;;;;;;;;;
;; Recursion notes
;; Notes taken through the little lisper/schemer,
;; seasoned/reasoned   

;; Define ami? as in am I an atom?
;; so it can be used.
(defun ami? (x)
  (not (listp x)))

;; Test to see if atom works
;; Are these atoms?
(ami? (quote ()))

(ami? 'atom)
(ami? (quote an-atom))
(ami? "a chicken atom?")
(ami? 2023)
(ami? #\i)
(ami? '*xyz^!)

;; Are these lists?
(listp 'eve)

(listp '(eve))
(listp '(Who came first adam or the caveman?))

;;end-recursion-notes
;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Useful built-in functions

(gensym)
;; Used to create random/crazy variable names as to make
;; sure they will not clash with any other variables.
;; Useful for creating throw away dynamic variables, like
;; in a macro.  They start with #: and lisp will not let
;; you use them directly, by name.

;; An example:
(defmacro split-list (value yes no)
  (my-let g-fun (gensym)
          `(my-let ,g-fun ,value
                   (if ,g-fun
                     (let ((head (car ,g-fun))
                           (tail (cdr ,g-fun)))
                       ,yes)
                       ,no))))

(my-let x 100
        (split-list '(10 30)
                    (+ x head)
                    nil)

(split-list (progn (princ "I'm Lost! ")
                   '(5 9))
            (format t "Splits into ~a and ~a." head tail)
            (format t "Not splitable!")


;; end-useful-built-in-functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;
;; Glossary

;; Anaphoric Macros - Macros that automatically generate variables
;; Let over lambda - a lexical closure
;; Tail Call - When a function in lisp calls itself [or another function]
;;             as it's very last action.
;; Variable Shadowing - Hiding one variable with another through precedence

;; end-glossary
;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Socket streams in clisp

;; Send a message from one clisp to another, on same or
;; seperate computer. Open two clisps one to act as server
;; and the other to act as a client.

(defparameter walkie-talkie-socket (socket-server 3232))
;; Open socket on server port 3232
;; Done on server 

(defparameter walktalk-stream (socket-accept walkie-talkie-socket))
;; Locks up socket and wait for a client connection
;; Done on server

(defparameter walktalk-stream (socket-connect 3232 "127.0.0.1"))
;; Connect to server ip and port. Now walktalk-stream can be seen
;; on both the server and client
;; Done on client

(print "Serve me the good stuff" walktalk-stream)
;; Print a message to the walktalk-stream
;; Done on client

(read walktalk-stream)
;; The server can read the message 
;; Done on server

(print "Pay up front for the good stuff!" walktalk-stream)
;; Send a message back to client
;; Done on server

(read walktalk-stream)
;; Read message from server
;; Done on client

(close walktalk-stream)
;; Make sure to close the stream on both client and server
;; Done on both client and server

(socket-server-close walkie-talkie-socket)
;; Close the socket on the server, else port will be locked up till
;; reboot.
;; Done on server

;; End of socket-stream example
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;
;; Lisp Data Types

Numbers: 321 3.21 -10e2 3/5 #c(2 3)
#c(2 3) = complex numebr
Strings: "Like me"
Symbols: me-a-symbol 'me-too
Lists: (a ("list" "of") '(lists) b c)
Characters: #\D #\e #\f #\space

;; end-lisp-data-types
;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;
;; Special Operators

;; quote   if      progn
;; let     let*    setq
;; flet    labels  macrolet
;; symbol-macrolet
;; block   return-from   tag body   go
;; multiple-value-call   multiple-value-bind

;; quote - prevents evaluation
;; if - boolean choice operations
;; progn - ability to sequence a number of forms

;; end-special-operators
;;;;;;;;;;;;;;;;;;;;;;;;

(apropos :count-d)
;; Apropos searches for symbol names

internal-time-units-per-second
;; Shows the number of internal time units in one second [for current machine] 

;;;;;;;;;;;
;; Packages

;; Packages are useful for preventing namespace
;; conflicts.

*package*
common-lisp:*package*
cl:*package*

:joemammy
keyword:joemammy
(eql :joemammy keyword:joemammy)
;; Keywords live in the keyword package

(mapcar #'package-name (package-use-list :cl-user))
;; Display packages inherited by common-lisp-user

(package-name (symbol-package 'package))
(package-name (symbol-package 'joedaddy))
(package-name (symbol-package :joedaddy))
;; Show which package a symbol is from.

(defpackage :leftoff-books-db
 (:use :common-lisp))
;; Define a new package and inherit from the common lisp package.

(in-package :leftoff-books-db)
;; Use the new package

(defpackage #:leftoff-books-db
 (:use #:common-lisp))
;; Define a package without interning

(in-package :cl-user)
;; Switch back to the default package of the repl.

(defpackage :leftoff.text-db
  (:use :common-lisp)
  (:export :open-db
           :save-db))
;; Export symbols in your package

(defpackage :left-off.user-db
  (:use :common-lisp :leftoff.text-db)
  (:import-from :mysql.plugin :dbrow-to-html))
;; Import individual symbol from a package.

(defpackage :leftoff.books-db
  (:use
    :common lisp
    :leftoff-text-db
    :mysqlite.plugin)
  (:import-from mysqlite.plugin :dbrow-to-html)
  (:shadow :looprow))
;; Exclude a symbol from a package with ":shadow".

;; end-packages
;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;
;; Lisp Libraries

;;;;;;;;;;;;
;; quicklisp

;; quicklisp - Common Lisp library manager.

;; To install quicklisp:
curl -O http://beta.quicklisp.org/quicklisp.lisp
sbcl --load quicklisp.lisp
(quicklisp-quickstart:install)

quicklisp commands:
(quicklisp-quickstart:help)
Display Help

(ql:quickload "system-name")
Installs a library 

(ql:quickload '(cl-who hunchentoot parenscript))
To install several libraries at once.

(ql:system-apropos "term")
Search for a library 

(ql:add-to-init-file)
Add quicklisp to init file, so it loads on lisp startup.
Adds to: ~/.sbclrc

;; end-quicklisp
;;;;;;;;;;;;;;;;

CL-WHO - library for converting Lisp expressions to XHMTL.
Hunchentoot - Common Lisp webserver / toolkit for dynamic web sites.
Parenscript - Compile lisp expressions into javascript.

;; end-lisp-libraries
;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;
;; Slime related

^c ^d h loop
;; Query Common Lisp Hyperspec (CLHS). In this case for: loop

^q,
;; To insert a comma on a previously evaluated line.
;; [comma is slime command, that normally only works
;; as first character, but if evaluated already
;; it may eat you]

C-M-q
;; Reindent an expression from the opening parenthesis

C-c M-q
;; Reindent from within the body of a function

C-c RET
;; Do this on the open paranthesis of a macro and it will
;; run slime-macroexpand-1. Which runs macroexpand-1
;; pretty printed.

,
;; Enter a command to slime.

,change-package
;; Change a package within slime.

;; end-slime-related
;;;;;;;;;;;;;;;;;;;;


Various Lisp Links: ^

 
Interesting articles
--------------------
The Nature of Lisp
http://www.defmacro.org/ramblings/lisp.html


Various resource links
----------------------
The common lisp wiki (has all kinds of links and resources)
http://www.cliki.net/

A page with a bunch of links and resources
http://www.apl.jhu.edu/~hall/lisp.html

clisp.org resources page
http://www.clisp.org/resources.html

Common Lisp Implementations: A Survey
http://common-lisp.net/~dlw/LispSurvey.html

Sockets [Network] are not part of ANSI-CL
Here are two attempts at providing one:
http://common-lisp.net/project/usocket/
http://common-lisp.net/project/cl-sockets/


Interactive tutorials
---------------------
ELM-ART interactive online lisp tutorial
http://art2.ph-freiburg.de/Lisp-Course

Lisp Tutor Jr (link is dead, maybe find a new one)
http://reed.cs.depaul.edu/peterh/Tools/lisptutor.html


Tutorial / Guides
-----------------
http://cs.gmu.edu/~sean/lisp/
Tutorials and Assorted Lisp Stuff (look for this section)


Pascal Costanza's Highly Opinionated Guide to Lisp
http://www.p-cos.net/lisp/guide.html

Lisp Primer
http://mypage.iu.edu/~colallen/lp/

Sample Code and exercises
http://www.dynamiclearningcenter.com/

AI Programming in Lisp
https://www.scm.tees.ac.uk/isg/website/index.php?page=lecture_sc

http://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html
http://www.informatimago.com/develop/lisp/l99/
L-99: Ninety-Nine Lisp Problems


Online Books
------------
Lisp Web Tales (Short book on lisp web dev)
http://lispwebtales.ppenev.com/

http://www.gigamonkeys.com/book/
Practical Common Lisp -Seibel

http://www.cse.buffalo.edu/~shapiro/Commonlisp/
Common Lisp: An Interactive Approach

http://www.cs.cmu.edu/~dst/LispBook/index.html
Common Lisp: A Gentle Introduction to Symbolic Computation

Successful Lisp: How to Understand and Use Common Lisp
http://www.psg.com/~dlamkins/sl/

Common Lisp the Language, 2nd Edition 
http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node1.html

Basic Lisp Techniques
http://www.franz.com/resources/educational_resources/cooper.book.pdf

The Common Lisp Cookbook
http://cl-cookbook.sourceforge.net/

On Lisp
http://www.paulgraham.com/onlisptext.html

Lisp Outside the Box  (an abandoned book about 1/4 complete, started in 2009)
http://lisp-book.org/


Books to Buy
------------
Land of Lisp
Even if you don't have the book,
you can check out most of the source code:
http://landoflisp.com/source.html

Artificial Intelligence: A Modern Approach
Paradigms of Artificial Intelligence Programming:
ANSI Common Lisp
Principles of Biomedical Informatics (most code in lisp)

Random Info
-----------
http://c2.com/cgi/wiki?search=lisp
http://plob.sourceforge.net/
http://www.lispworks.com/documentation/HyperSpec/Front/index.htm
http://hyperpolyglot.org/lisp

ANSI and GNU Common Lisp Document
http://www.mat.uc.pt/~pedro/cientificos/funcional/lisp/gcl_toc.html

Videos
------
Franz developers of Allegro CL have training videos:
http://www.franz.com/services/classes/download.lhtml

Structure and Interpretation of Computer Programs
MIT's course using scheme
http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/

http://coursehero.org.s3.amazonaws.com/sites/default/files/videos/HARCS50Week11cLec30645.flv
Introduction to Lisp (Havard CS51) [23rd video is on Lisp]

An Brief Introduction to Lisp (pt 1-4) [Oreilly]
http://www.youtube.com/watch?v=M-BFgErib4k
http://www.youtube.com/watch?v=jvnwXHsL8eo
http://www.youtube.com/watch?v=xfh-oXjS73I
http://www.youtube.com/watch?v=g_RjV5Q3sTY

Lisp Screencast 01: Macros
http://www.adztec-independent.de/2009/01/lisp-screencast-01-macros/


Introduction to Artificial Intelligence (ASU-FEAS)
http://rakaposhi.eas.asu.edu/cse471/
(Has 3 videos on lisp)
-------------------------------
Lecture 1 on the anatomy of lisp:
http://www.youtube.com/watch?v=Ot1CgsETQCc
http://rakaposhi.eas.asu.edu/cse471/lisp-anatomy.avi

Lecture 2 on functions as first-class objects:
http://www.youtube.com/watch?v=Sfa1lBNZ6zQ
http://rakaposhi.eas.asu.edu/cse471/lisp-functions-are-first-class.avi

Lisp Recitation lecture by Will Cushing ([Jan 12, 2012]):
http://rakaposhi.eas.asu.edu/cse471/cse471-s12-lisp-recitation-will.MP4


Lisp IDEs
--------------
http://www.daansystems.com/lispide/
LispIDE


Useful Libraries
----------------
Linedit 
Provides better line-editing in the REPL
http://common-lisp.net/project/linedit/


EmacsLisp
---------
An Introduction to Programming in Emacs Lisp
http://www.gnu.org/software/emacs/manual/html_mono/eintr.html


Lisp Repositories
-----------------
CMU Common Lisp Repository
http://www.cs.cmu.edu/afs/cs.cmu.edu/project/ai-repository/ai/lang/lisp/0.html

http://www.cs.cmu.edu/Groups/AI/html/faqs/lang/lisp/part1/faq.html

^

default