Notes taken while reading:
Learn Lisp the Hard Way


; Leftoff

; Slime shortcuts
; ,cd - change directory
; ,quit - exit slime

; In-place destructive operations are prepended with an "n"

(format nil "~C" #\greek_small_letter_lambda)
; Print lambda greek character

(string #\greek_small_letter_lambda)
; Print lambda greek character
; (string) can only take one argument, a char or a string

(coerce '(#\greek_small_letter_lamda
          #\greek_small_letter_delta) 'string)
; Print more than one greek character in a list with
; coerce.

(char-code #\e)
; Get the code for the lowercase letter e

(code-char #x65)
; Get the character for the hex code 0x65

(write "who are you?")
; Write lowest level way to write/print to screen.
; It is powerful yet very general

(write 160 :base 16 :radix t)
(write 160 :base 8 :radix t)
(write 160 :base 2 :radix t)
; Use write to find out hex, octal, and binary codes
; for the decimal number 160

(print "you like newlines before printing?")
; Print to *standard-output* with newline before

(prin1 "prints readably for the lisp reader")
; Able to be read back into the lisp reader as data.
; Does not print newline before, and does not
; leave whitespace after.

(princ "Hello \"guess\" who I print for?")
(princ #\greek_capital_letter_sigma)
(write #\greek_capital_letter_sigma :escape nil)
; Prints out for the user and not for the lisp reader.
; Escape characters will not be escaped.
; This can also be achieved with write passing escape nil

(format nil "Hello, ~A how are you?" "ladies")
(format nil "Hello, ~A and ~A get ready for..."
		 "ladies" "gentlemen")
(format t "Hi, ~S!" "guys")
(format t "Hey my ~W!" "peeps")		 
; Format uses control sequences to print strings
; They will eat an argument and spit them out
; ~A - aesthetic (prints like princ)
; ~S - standard control seq (prints like prin1)
; ~W - write control seq (prints like write)
; nil is the output stream
; t is the output stream (*standard-output*) (format only)
; t is *terminal-io* for other printing functions

(format nil "~%testing")
; ~% inserts a newline

(format nil "test~&ing")
(format nil "~&testing")
; ~& will only insert a newline if not at the beginning of a line

(truename ".")
; get current working directory

(pathname-directory (truename "."))
; Display current working directory broken up without /'s
; "home" "username" "learn" "lisp" "some-directory"

(pathname-name (truename "/home/envia/lrn/lisp/llthw/ex-1-5.lisp"))
; Show filename without extension

 (pathname-type (truename "/home/envia/lrn/lisp/llthw/ex-1-5.lisp"))
; Show file extension

(file-namestring (truename "/home/envia/lrn/lisp/llthw/ex-1-5.lisp")
; Show file name

(pathname-name (truename "."))
;; Returns nil on *nix
;; Think it may have a value on windows need to check
;; when I get a win box

(pathname-type (truename "."))
;; Returns nil on *nix box
;; May return something else on windows

(make-string-input-stream "hey there!")
;; Creates an input stream object from a string
;; String stream

(read (make-string-input-stream "go away!"))
;; Wraps the input stream in a read form.
;; It will think it is a symbol and only return
;; "go" as the input is not readable to lisp

(read (make-string-input-stream "\"go away!\""))
;; Same as above but it is now readable since
;; it has the an extra set of escaped quotes
;; it will now return "go away!"

(with-input-from-string (s "Welcome home darling!")
  (read s))
;; Read make lisp read in the data, so it will see
;; this string as a symbol and return: welcome

(with-input-from-string (s "Welcome home darling!")
  (read s)
  (read s)
  (read s))
;; Returns: darling

(with-input-from-string (s "\"Welcome??? Where's my dinner!\"")
  (read s))
;; With the extra escaped quotes lisp can read return
;; the entire string, rather than individual strings.

(with-output-to-string (pout)
  (with-input-from-string (no-pout-in "\"No more whining please!\"")
    (let ((io (make-two-way-stream no-pout-in pout)))
      (format io "~A Wah wah, won't anyone listen?" (read io)))))
;; Create a bi-directional stream.
;; Creating an output stream bound locally to pout.
;; Then creating an input stream bound locally to no-pout-in
;; Make a bi-directional steam out of two above and bind it to io

(with-open-file (s "./lisp-files-stream.txt" :direction :output :if-does-not-exist :create :if-exists :supersede)
  (format s "I ate a little kittie, ~%It tasted tasty, ~%His buddies did not seem to like it....~%"))
;; Use a file stream to write a file to the current directory

(with-open-file (s "./lisp-files-stream.txt" :direction :input)
  (format t "~&;;; ~A" (read-line s)))
;; Read the first line of a file into the repl

(with-open-file (s "./lisp-files-stream.txt" :direction :input)
  (do ((line (read-line s) (read-line s nil 'eof)))
      ((eq line 'eof) "-- Jack Parsons")
    (format t "~&;;; ~A~%" line)))
;; Read a file into the repl printing it and appending
;; some text to it

(with-open-file (b "./binary-file-stream-txt" :direction :output :element-type 'unsigned-byte :if-exists :supersede)
  (write-byte 99 b)
  (write-byte 111 b)
  (write-byte 109 b)
  (write-byte 109 b)
  (write-byte 111 b)
  (write-byte 110 b)
  (write-byte 32 b)
  (write-byte 108 b)
  (write-byte 105 b)
  (write-byte 115 b)
  (write-byte 112 b))
;; Write some text to a file with a binary stream

;;(y-or-n-p "Help me?")
;;(yes-or-no-p "Want to do it again?")
;; These can be used to prompt a user

(pprint '(defun ribbit (x y z) "ribbit ribbit" (let ((ribbit 1) (ribbits 2) (ribbitz 3)) (values (list frog bullfrog treefrog) (list frogleg frogeyes frogtoes)))))
;; An example of how lisp's pretty printer can take a
;; long input and break it up into a prettier format

;; Lisp reader will wait for user to input data and hit enter

;;(eval (read))
;; Have the lisp reader evaluate what user inputs

;;(let ((dest (make-list 5)))
;;  (read-sequence dest *standard-input*)
;;  dest)
;; Specify how much the lisp reader will read; before hand

(let ((dest (list)))
  (read-sequence dest *standard-input*)
;; In this case it will return nil immediately
;; as no room has been allocated for the lisp
;; reader to read. A zero lenght buffer

;;(defparameter *buf8* (make-list 8))
;;(read-sequence *buf8* *standard-input*)
;; Will read in 8 characters enter key
;; uses up one each time it is hit

(consp 33)
(consp "z")
(consp 'r)
(consp (cons 'x 'y))
(cons 'x 3)
(cons 4 "seven")
(cons "s" 't)
;; Using cosnp to find out what is and is not
;; a cons-cell

(cons 3 2)
(cons "five" "six")
;; Cons can be used to create a cons-cell

(equal (cons 'a 'b) '(a . b))
;; See if consing 'a 'b is equal to '(a . b)

(car (cons 'a 'b))
(first (cons 'x 'y))
;; Get the first value in a cons-cell with car
;; First can also be used

(cdr (cons 'a 'b))
(rest (cons 3 4))
;; Get the second value in a cons-cell with cdr
;; Rest can also be used

(last '(1 2 3 4))
(last (cons 9 (cons 8 (cons 7 nil))))
;; Last can be used to grab the last element in a list or
;; cons-cell

(cons 6 (cons 5 (cons 4 nil)))
;; Consing together a non dotted list

(list 7 8 9)
;; Create a list

(equal (list 6 7 8) (cons 6 (cons 7 (cons 8 nil))))
;; See if using list and consing conses are equivalent

(list 4 (list 5 6) (list 7 (list (list 5) 2 1 3)))
;; Creating nested lists with list

(car (car (cons (cons 4 5) 8)))
(car (cdr (cdr (cdr (list 5 4 3 2 1)))))
(cadddr (list 9 8 7 6 5))
;; Cars and cdrs can be chained also

(nth 5 (list 1 2 3 4 5 6 7))
;; nth can be used to get to a chosen element

(defvar *crack* nil)
(push 4 *crack*)
(push 5 *crack*)
(push 6 *crack*)
(push (list 4 5) *crack*)
(pop *crack*)
(pop *crack*)
;; You can destructively add values to a list with push
;; and remove the elements with pop

(append (list 'a 'b 'c) (list 4 5 6))
(append (list 'x 'y) (list 1 2) (list 'm 1))
;; Append joins two list together the second
;; is added after the first and so on.

(defvar *cuties* (list 'ash 'kate))
(append (list 'mary) *cuties* '(vjay))
;; Append is non destructive
;; It will not change the variable

(defparameter *sexy* (list 'danny 'kevron))
(nconc *sexy* '(rob))
;; nconc is the destructive version of append
;; it will add to the variable *sexy*

(quote (a b c))
'(a b c)
(list 'a 'b 'c)
;; Different ways to make a list "tree structure"
;; list will return the list, while quote will
;; not evaluate it
;; These are equivalent
;; As seen below

(equal (quote (a b c)) '(a b c))
(equal '(a b c) (list 'a 'b 'c))
;; Testing to see if they are the same

(defparameter *checkin* 5)
(list 7 *checkin* 9)
'(7 *checkin* 9)
(list (+ 6 5) (+ 8 7) (+ 2 1))
'((+ 6 5) (+ 8 7) (+ 2 1))
;; Example of quoting not evaluating

(list 9 (list 8 7) (list 6 (list (list 5) 4 3 2)))
'(9 (8 7) (6 ((5) 4 3 2)))
;; Quoting makes it easier to create deeply nested
;; structures.
;; Don't use quoted data for mutation; as it is
;; undefined by the common lisp lang spec. and is
;; implementation dependant

'((x . 20) (y . 50) (z . 150))
;; alist is a list of cons cells (association list)

(list 'smart 'kai 'sexy 'kat 'crazy 'brat)
(getf (list 'smart 'kai 'sexy 'kat 'crazy 'brat) 'crazy)
(getf (list :kitty 'didget :doggie 'nika :hedgehog 'george) :kitty)
;; plist (property list) have odd elements as keys
;; and even elements as the value
;; getf can be used to grab the value by the key

(getf (list :tv 'big :spoon 'silver :door 'wood) :fork 'not-here)
;; By default getf will return nil if key not found. An
;; alternative return value can be given.

(cons :d (cons 4 (list :a 1 :b 2 :c 3)))
;; Cons can be used to add to an existing plist

(let ((plist (list :a 'taco :b 'hamburger :c 'steak)))
	   (append (list :d 'salad :e 'nuggets) plist))
;; Append can be used to add to a plist

(defparameter *plist* (list :one 'cow :two 'leech :c "help"))
(setf (getf *plist* :c) 'lizard)
(getf *plist* :c)
;; Setf can be used to mutate plists
(setf (getf *plist* :d) 'gorilla)
;; Keys can also be added with setf
(remf *plist* :one)
;; Remf removes keys from a plist

'((house1 . brown) (house2 . green) (house3 . blue))
(list (cons :bar "chocolate") (cons :butter "peanut"))
;; alist is a list of cons-cells
;; The first cons-cell element is the key while
;; the rest is the value

(assoc 'blankey '((rock . hard) (blankey . soft) (cracker . crunchy)))
;; Using assoc the alist key can be used to return
;; the entire cons-cell

(assoc "rabbit" '((katty . black) ("rabbit" . green)) :test #'equal)
(assoc "rabbit" '((cat . black) ("rabbit" . green)) :test-not #'equal)
(assoc #(#\f #\o #\o) '((x . y) (#(#\f #\o #\o) . sucka)) :test #'equalp)
;; Assoc can take test arguments