From 067aebaf81069a7fa9f764db22b17509db371f3a Mon Sep 17 00:00:00 2001 From: efim Date: Sun, 24 Jul 2022 11:52:07 +0000 Subject: [PATCH] exercises and notes from "Gentle introduction" --- FSMs.lisp | 13 + applicative-style.lisp | 99 ++++++++ arrays.lisp | 80 +++++++ assignment.lisp | 48 ++++ basics.lisp | 365 +++++++++++++++++++++++++++++ break-and-error.lisp | 23 ++ hello.lisp | 4 + input-output.lisp | 117 +++++++++ iteration-and-block-structure.lisp | 98 ++++++++ list-structure.lisp | 61 +++++ macro-and-compilartion.lisp | 200 ++++++++++++++++ optional-arguments.lisp | 59 +++++ packages.lisp | 16 ++ quicklisp-thing.lisp | 66 ++++++ recursion.lisp | 100 ++++++++ session1.log | 0 structures-and-type-system.lisp | 116 +++++++++ test-input.lisp | 3 + toolkit.lisp | 22 ++ trace-and-dtrace.lisp | 13 + vars-and-effects.lisp | 94 ++++++++ 21 files changed, 1597 insertions(+) create mode 100644 FSMs.lisp create mode 100644 applicative-style.lisp create mode 100644 arrays.lisp create mode 100644 assignment.lisp create mode 100644 basics.lisp create mode 100644 break-and-error.lisp create mode 100644 hello.lisp create mode 100644 input-output.lisp create mode 100644 iteration-and-block-structure.lisp create mode 100644 list-structure.lisp create mode 100644 macro-and-compilartion.lisp create mode 100644 optional-arguments.lisp create mode 100644 packages.lisp create mode 100644 quicklisp-thing.lisp create mode 100644 recursion.lisp create mode 100644 session1.log create mode 100644 structures-and-type-system.lisp create mode 100644 test-input.lisp create mode 100644 toolkit.lisp create mode 100644 trace-and-dtrace.lisp create mode 100644 vars-and-effects.lisp diff --git a/FSMs.lisp b/FSMs.lisp new file mode 100644 index 0000000..faec188 --- /dev/null +++ b/FSMs.lisp @@ -0,0 +1,13 @@ + +;; exmple of FSM +;; vending machine +;; - gum :: 15 cents +;; - mints :: 20 cents +;; any combination of +;; DIME - 10c +;; NICKEL - 5c +;; if enough money is in, press of either button would get you the product and change +;; pressing coin return at any time will return amount equal to being put in so far + +;;; and the exercise is to use macro to compile FSM with functions for states, from defstate & defarc structures +;; that seems cool diff --git a/applicative-style.lisp b/applicative-style.lisp new file mode 100644 index 0000000..c1e064c --- /dev/null +++ b/applicative-style.lisp @@ -0,0 +1,99 @@ +;;; applicative programming based on idea that functions are data +;; base primitive is #'funcall + +(funcall #'cons 'a 'b) +(setf fn #'cons) +fn +(type-of fn) +(funcall fn 'c 'd) + +;; mapcar is most frequently used +(defun power-3 (n) + (* n n n)) +(power-3 3) + +(mapcar #'power-3 '(1 2 3 4 5)) + +(mapcar (lambda (n) (* n n)) '(1 -1 4 -5)) + +(mapcar (lambda (name) `(hello there ,name)) '(john efim baba)) + +(quote thing) + +(lambda (num) `(I like my number ,num)) +#'(lambda (num) `(I like my number ,num)) + +(defun flip (directions) + (mapcar (lambda (direction) + (cond ( (eq direction 'UP) 'DOWN) + ((eq direction 'DOWN) 'UP) + (t 'UNKNOWN))) + directions)) + +(flip '(UP UP UP DOWN)) +(flip '(UP UP UP DOWN heiho)) + +(< 1 5) + +(defun find-first-around-10 (numbers number) + (find-if (lambda (num) (if (< (abs (- num number)) 10) t)) numbers)) + +(find-first-around-10 '(100 150 149 200 ) 148) ; nice =D + +(listp "hello") +(listp '(1 2 )) +(listp '()) + +(setf my-list '(1 2 "hhi")) +(find-if #'listp '("hello" 12 my-list (1 2))) +(find-if #'listp `("hello" 12 ,my-list (1 2))) +;; cool, there's ' quote and ` backquote, which allows for , evaluation points + +;; for shorter lambda, I guess I'd also want to learn big and common libraries +;; like Alexandria, rutils, Serapeum, generic-cl +;; https://lispcookbook.github.io/cl-cookbook/cl21.html#shorter-lambda + +;;; reduce operation. single operation, without separate starting element, just whole list into single value +(reduce #'+ '(1 2 3 15)) +(reduce #'+ nil) ; from left to right + +;;; task of creating single set from list of lists. +;; solution is to REDUCE and use UNION +;; but hell, how would I remember, or found with apropos? +;; there are set-* functions, but union is a separate name =C + +(setf my-list-of-lists '((a b c) (c d a) (f b d) (g))) +(reduce #'append my-list-of-lists) +(reduce #'union my-list-of-lists) + +;; well, there's sly-documentation - shows small doc +;; and there's sly-documentation-lookup - directs to website with lots of info +;; still not quite sure how would I have looked up union when it doesn't quite connect to set + +;;; mapcar can take several lists and function of corresponding arity will be called with consequtive elements from those lists +;;; as if they were zipped + +(mapcar (lambda (name job) `(,name gets ,job)) + '(tom jerry simba) + '(cleaning cooking roasting playing)) + +(setf words '((one . un) + (two . du))) + +(cdr (first words)) + +;; :from-end t - can be used with many applicative style funcions. Especially significant with REDUCE + +;;; closure (as created in place of lambda creation) +;;; has parent scope to the function. +;;; basic parent is global scope + +(defun make-greater-than-p (n) + (lambda (x) (> x n))) + +(setf my-pred (make-greater-than-p 5)) + +(funcall my-pred 3) +(mapcar my-pred '(1 3 17 3)) +(find-if my-pred '(1 4 16 2 5)) +(delete-if my-pred '(2 5 17 3 6)) diff --git a/arrays.lisp b/arrays.lisp new file mode 100644 index 0000000..5138046 --- /dev/null +++ b/arrays.lisp @@ -0,0 +1,80 @@ +;;; constant timem to access + +(make-array 5 :initial-element 1) +(make-array 6 :initial-contents `(a e i o u j)) ; should match with size +(make-array 3) ; elements are implementation dependent + +*print-array* + +;;; hash tables - more performant, but a bit more complicated api than alist +(setf my-table (make-hash-table)) +(gethash 'a my-table) +(setf (gethash 'a my-table) '(mary doctor)) + +;;; property list +;; (ind-1 value-1 ind-2 value-2 ...) +;; so all on one level instead of cons or lists +;; GET function retrieves values from property list of a symbol. +;; so first we put some properties to symbol +(setf (get 'fred 'sex) 'male) +(setf (get 'fred 'age) 33) +(get 'fred 'sex) +(describe 'fred) ; plist is printed in repl + +(remprop 'fred 'age) + +(symbol-plist 'fred) + +(defun subprop (symbol item property) + (setf (get symbol property) + (remove item (get symbol property)))) ; well that's exercise for lisp properties, ok + +(setf (get 'fred 'syblings) '(jeorge tom)) +(get 'fred 'syblings) +(subprop 'fred 'tom 'syblings) + +;; allright, let's do exercise about random and histogram +;; +;; (new-histogram 11) +;; (dotimes 200 +;; (record-value (random 11))) +;; (print-histogram) + +(defvar *hist-array*) +(defvar *total-points*) + +(defun new-histogram (size) + (setf *hist-array* (make-array size :initial-element 0)) + (setf *total-points* 0)) + +(new-histogram 11) + +(length *hist-array*) +(aref *hist-array* 1) +(incf (aref *hist-array* 1)) + +(defun record-value (n) + "Adds value h to corresponding bucket of *HIST-ARRAY* and increases *TOTAL-POINTS*." + (if (> n (length *hist-array*)) (error "nubmer is too big")) + (incf (aref *hist-array* n)) + (incf *total-points*)) + +;; next - print + +(defun print-hist-line (i) + (let* ((hist-value (aref *hist-array* i)) + (hist-line (make-string hist-value :initial-element #\*))) + (format t "~&~2S [ ~3S] ~S" i hist-value hist-line))) + +(dotimes (i 200) + (record-value (random (length *hist-array*)))) + +(print-hist-line 2) + +(defun print-histogram () + (dotimes (i (length *hist-array*)) + (print-hist-line i))) + +(print-histogram) + +;;; yay! diff --git a/assignment.lisp b/assignment.lisp new file mode 100644 index 0000000..cd30443 --- /dev/null +++ b/assignment.lisp @@ -0,0 +1,48 @@ + +(setf circ (list 'foo)) +(setf (cdr circ) circ) + +circ + +;;; setf modifies "pointers" +;;; and getter returns a reference +;;; so using setf with getter as "place" works as a setter +;;; +;;; append - nondestructive +;;; nconc - destructive merging of lists + +(nconc '(hello lists) '("and" "with" other 15 "values")) + +;; subst - nondesctructive +;; nsubst - destructive + +(setf tree '(i say (e i (e i) o))) +(subst 'a 'e tree) +tree + +(nsubst 'a 'e tree) +(nsubst 'cherry '(a i) tree :test #'equal) +;; this modifies the list + +;;; exercise, +;; chop - redule non nil list to list of head +(defun chop (x) + (setf (cdr x) nil)) + +(setf my-list '(1 2 "hello")) +(chop my-list) +my-list + +(defun ntack (x a) + (setf (cdr (last x)) (list a))) +(setf my-test-ntack-list '(1 2 "hello")) +(ntack my-test-ntack-list 'boo) +my-test-ntack-list + +;; and more recursion +(setf h '(hi ho)) +(setf (cdr (last h)) h) + +;;; setq - before "generalized variables", only sets value of ordinary variables +(setq x '(slings and arrows)) +(setq (cdr x) (list "hello")) ; variable name is not a symbol diff --git a/basics.lisp b/basics.lisp new file mode 100644 index 0000000..9ee7308 --- /dev/null +++ b/basics.lisp @@ -0,0 +1,365 @@ +(FIRST '(5 2 3)) +(SECOND '(5 2 3)) +(THIRD '(5 2 3)) +(REST '(5 2 3 5 1 6)) + +(cons 1 '( 2 )) ; adds number to the list +(cons 1 2) ; just a cons element +(cons 'SINK '(OR SWIM)) ; adds symbol to the list +(cons 'SINK 'SWIM) ; just a cons element with symbols +(cons 'start nil) ; list is when last cons ends with `nil +(cons 'start (cons 'end nil)) ; if we are to construct list from cons cells (and not from print notation) +(cons 'nil 'nil) ; putting nil into CDR means having list with that item as CAR +(cons '(PHONE HOME) nil) +;; even though `nil is same as '() many properties of lists hold only for non-empty lists, i.e +;; with at least one cons cell +;; for example main relationship between CAR, CDR & CONS +(equal + '(1 2 3 4) + (cons + (car '(1 2 3 4)) + (cdr '(1 2 3 4)))) +;; doesn't work for () : +(equal + '() + (cons + (car '()) + (cdr '()))) + +(cons + (car '()) + (cdr '())) ; => (NIL) + +;;; exercises 3 +(defun half (x) + (/ x 2)) + +(defun cube (x) + (* x x x)) + +(defun pythag (x y) + (sqrt (+ (* x x) (* y y)))) + +;; variables /are named by/ symbols, they are *not* symbols +;; funcitons are /aldo named by/ symbols + +;;; symbols and lists as data +;; use ` - tilde to tell lisp interpreter +;; to treat symbol not as a name for variable (and evaluate to its value) +;; but to treat it as symbol (data) +;; +;; most symbols need to be quoted to be treated as symbols +;; some exceptions are t and nil which are self evaluating + +(defun riddle (x y) + (list `why `is `a x `like `a y)) +(riddle `raven `desk) + +;;; Evaluation Rule for quoted Quoted Objects: +;;; quoted object evaluates to the object itself without the quote + +;; 3 ways of creating lists +`(foo bar baz) ; everything inside list is not evaluated + +(list `foo `bar `baz (* 33 33)) ; allows for "computed elements"" " +(cons `foo `(bar baz)) + +;; 3.11 +(defun longer-than (l1 l2) + (> (length l1) (length l2))) + +(defun call-up (caller callee) + (list `hello callee `this `is caller `calling)) + +(defun crank-call (caller callee) + `(hello callee this is caller calling)) + +;; 3.22 c +(defun myfun (a b) + (list (list a) b)) + +;; 3.22 d +(defun firstp (item list) + (equal item (first list))) + +;; 3.22 e +(defun mid-add1 (list) + (cons + (car list) + (cons (+ 1 (cadr list)) + (cddr list)))) + +;; 33.2 f +(defun f-to-c (farenheit-temp) + (/ (* 5 (- farenheit-temp 32)) 9)) + +(symbol-name `equal) +(symbol-function `equal) + +(symbol-name `lambda) +(symbol-function `lambda) + +(eval (list `cons t nil)) + +;;; equivalence of COND, IF, AND & OR - conditionals + +;; (and x y z w) + +;; (equal 1 1 1) + +(setq + x 1 + y nil + z 1 + w 1) + +(cond + ((not x) nil) + ((not y) nil) + ((not z) nil) + ((not w) nil) + (t t)) + +(defun boilingp (temp scale) + (cond ((and (equal scale `celsius) + (> temp 100)) t) + ((and (equal scale `farenheit) + (> temp 212)) t))) + +(defun boilingp-2 (temp scale) + (or + (and (equal scale `celsius) (> temp 100)) + (and (equal scale `farenheit) (> temp 212)))) + +(cond) + +;; 4.28 +(if (oddp 5) (evenp 7) `foo) +(or (and (oddp 5) (evenp 7)) `foo) +;; not sure what's up with that +;; was that attempt to rewrite if into or&and? +;; So, that written correctly! I get stops because of forced debugger! +;; (step (eval (or (and (oddp 5) `(evenp 7)) ``foo))) +(eval `(evenp 7)) +(eval ``foo) + + +(step (if (oddp 5) `yes `no)) + +(defun my-abs (x) + (if (< x 0) (- x) x)) + +(step (my-abs 15)) + +;;; variables & side-effects +(defun price-change (old new) + (let* ((diff (- new old)) + (proportion (/ diff old)) + (percentage (* proportion 100.0))) + (list `widgets `changed `by percentage `percent))) + +;;; 5.6 die exercise +(defun throw-die () + "Return random value [1 6]." + (+ 1 (random 6))) + +(defun throw-dice () + "Return list of 2 random die trows" + (list (throw-die) + (throw-die))) + +(defun snake-eyes-p (throw) + "True if both dice in throw equal to 1." + (and (equal 1 (first throw)) + (equal 1 (second throw)))) + +(defun boxcars-p (throw) + "True if both dice in throw equal to 6." + (and (equal 6 (first throw)) + (equal 6 (second throw)))) + +(defun instant-win-p (throw) + "True if sum of dice in throw is 7 or 11" + (let ((sum (+ (first throw) (secon throw))) + (special-values (list 7 11))) + nil)) + +;; they meant type of word that is an article +(setq articles `(the a an)) +(defun contains-article-p-1 (list) + "Check whether article contains in the list." + (intersection articles list)) + +(setq test-sentence `(we will rock the boat)) + +;; checks for each article +(mapcar (lambda (article) + (member article test-sentence) + ) articles) + +;; attempt to fold them into single boolean with or +(apply `or (mapcar (lambda (article) + (member article test-sentence) + ) articles)) + +(step (apply `+ `(1 2 3))) +(apply `equal `(2 3)) +(equal 2 3) +(or nil nil t) +(apply `or `( nil nil t)) +(step (apply `or (list nil nil nil))) + +(setq comparing-sentence `(large red shiny kube -vs- small shiny red four-sided pyramid)) + +(list + (length (intersection + (cdr (member `-vs- comparing-sentence)) + (cdr (member `-vs- (reverse comparing-sentence))))) + `common `features) + +;;; 6.9 programming with tables (as lists) +(setq table1 `((object1 large green shiny cube) + (object2 small wihte dull cube) + (object3 large red shiny pyramid) + (object3 green shiny sphere))) + +(setf quality-table + `((green . color) + (red . color) + (white . color) + (cube . shape) + (pyramid . shape) + (sphere . shape) + (shiny . luster) + (dull . luster) + (large . size) + (small . size) + )) + +(defun quality (x) + "Get from hardcoded table." + (cdr (assoc x quality-table)) + ) + +(defun description (key) + "Get description of object from hardcoded table." + (cdr (assoc key table1))) + +(description `object2) +;; notion of ~sublis~ function instead of mapcar for getting types of properties + +(defun differences (x y) + "Get different properties from hardcoded table." + (set-exclusive-or (description x) + (description y))) + +(differences `object1 `object2) + + +(remove-duplicates (sublis quality-table (differences `object1 `object2))) + +;;; 6.35 finite state automata + +(setq nerd-states `((sleeping . eating) + (eating . waiting-for-a-computer) + (waiting-for-a-computer . programming) + (programming . debugging) + (debugging . sleeping))) + +(defun nerdus (current-state) + "Return next state for the nerdus in the provided CURRENT-STATE." + (cdr (assoc current-state nerd-states))) + +(nerdus `programming) + +(defun sleepless-nerd (current-state) + "Nerd that never sleeps." + ;; consequtive `sleep -> sleep` considered to be impossible + (let ((possible-state (nerdus current-state))) + (if (equal possible-state `sleeping) + (nerdus `sleeping) possible-state))) + +(sleepless-nerd `sleeping) +(sleepless-nerd `debugging) + +(nerdus `playing-guitar) + +(defun nerd-on-caffeine (current-state) + "Advancing two states in one step." + (nerdus (nerdus current-state))) + +(nerd-on-caffeine `sleeping) + +;; nested lists are trees and there are functions that can be used on them +(subst `bb `aa `(In this list symbol aa would be substituted)) +;; args are NEW OLD TREE +;; and whole tree structure is checked: + +(subst `bb `a `((a tree) In this list symbol (a hatter) aa would be substituted (a test))) + +;; sublis takes many substitutions, instead of first two args, the plist +(defun royal-we (sentence) + "Substitute all I to We." + (subst `we `i sentence)) + +;;; eq compares addresses, so lists would not be eq +;;; equal compares elements of the lists +;; symbols are singletons, so using ~eq~ is ok +;; numbers might not be primitive in lisp implementations! +;; +;; eql - compares addresses in general case, for numbers: if of the same type compares values +(eql 3 3) +(eql 3 3.0) +;; to test value of the numbers across types +;; but works only with numbers, ok! +(= 3 3.0) + + +;;; Keyword arguments +:keyword-symbol ; evaluates to self, cannot change value +keyword-symbol ; different and not equal to actual keyword +(symbolp :keyword) +(keywordp :keyword) +(keywordp `keyword) + +;;; 7.3 Applicative programming +;; one of the styles, along with recursive and iterative + +(funcall #'cons 'a 'b) +(setf fn #'cons) +fn +(type-of fn) +(funcall fn 'c 'd) + +;; using mapcar +(defun squaring (x) + "Square input." + (* x x)) +(squaring 9) +(squaring '(1 2 2 3)) + +(mapcar #'squaring '(1 2 2 3 9)) + +(mapcar #'zerop '(20 340 0 -5 -6)) + +(mapcar #'(lambda (x) `(hi there ,x)) + '(joe fred martha)) +;; 195 +(funcall #'(lambda (x) + (or (equal x t) + (equal x nil))) 1) + +(defun half (x) + "" + (/ x 2.0)) + +(defun average (x y) + "" + (+ (half x) (half y))) + +(defun fact (n) + "" + (cond ((zerop n) 1) + (t (* n (fact (- n 1)))))) + +(fact 4) diff --git a/break-and-error.lisp b/break-and-error.lisp new file mode 100644 index 0000000..e0963cd --- /dev/null +++ b/break-and-error.lisp @@ -0,0 +1,23 @@ + +(defun analyze-profit (price comission-rate) + (let* ((comission (* price comission-rate)) + (result (cond ((> 100 comission) 'rich) + ((< 100 comission) 'poor)))) + (break "~&The value of result is ~S" result) + (format t "~&I predict that you will be: ~S" result) + result)) + +(analyze-profit 2200 0.06) +(analyze-profit 2000 0.05) + +;;; So - debugger keys and functions +;; C-j and C-k are for moving between frames +;; for frame context commands R - return from frame with particular value (sly-db-return-from-frame) +;; x - step over, s - step +;; e - eval in frame, i - inspect in frame (show additional info on evaluated value) +;; RET - toggle details for current frame +;; v - show frames code +;; d - pretty-print-eval-in-frame +;; (searching all of functions by going into debugger bugger and looking at *helpful* (C-h C-f) "sly-db-" + +;; could also try to recompile thing, maybe r for restart, or R to return with value 1 from last frame and check how it all works diff --git a/hello.lisp b/hello.lisp new file mode 100644 index 0000000..234c879 --- /dev/null +++ b/hello.lisp @@ -0,0 +1,4 @@ +(defun hello () + (write-line "What is your name?") + (let ((name (read-line))) + (format t "Hello, ~A.~%" name))) diff --git a/input-output.lisp b/input-output.lisp new file mode 100644 index 0000000..6273896 --- /dev/null +++ b/input-output.lisp @@ -0,0 +1,117 @@ +;;; that's chapter 9 +(format t "hello") + +;; so here's difference with Elisp, format takes "destination" as first attribute +;; needs 't to write to screen, others to file or such +;; in Elisp returns a string, right? yes + +(format t "~&There are old pilots,~&and there are bold pilots,~&but there are no bold old pilots.") + +(defun draw-line (n) + (cond ((zerop n) (format t "~%")) + (t (format t "*") + (draw-line (- n 1))))) + +(draw-line 5) + +(defun draw-box (height width) + (cond ((zerop height) (format t "~%")) + (t (draw-line width) + (draw-box (- height 1) width)))) + +(draw-box 3 15) + +(defun draw-ttt-row (row) + (labels ((as-drawable (cell-state) + (if (null cell-state) " " + cell-state))) + (format t "~&~A|~A|~A~%" (as-drawable (first row)) (as-drawable (second row)) (as-drawable (third row))))) + +(draw-ttt-row '(X O nil)) + +(defun draw-ttt-board (table) + (draw-ttt-row (first table)) + (format t "-----~%") + (draw-ttt-row (second table)) + (format t "-----~%") + (draw-ttt-row (third table))) + +(draw-ttt-board '( (x x nil) (nil o nil) (x o x))) + +;;; the read function + +(defun my-square () + (format t "Please type in a number: ") + (let ((x (read))) + (format t "~&The number ~S squared is: ~S" x (* x x)))) + +(my-square) + +(defun test-y-or-n () + (if (yes-or-no-p "~&Answer yes or no") + (format t "~&this is the yes response") + (format t "~&this is no response"))) + +(test-y-or-n) + +;; reading from the file + +(defun get-tree-data (path-string) + (with-open-file (stream path-string) ; both absolute from ~ and relative work + (let* ((tree-loc (read stream)) + (tree-table (read stream)) + (num-trees (read stream))) + (format t "~&There are ~S trees on ~S." num-trees tree-loc) + (format t "~&They are ~S" tree-table)))) + +(get-tree-data "./test-input.lisp") ; cool + +;; so just dumped elisp structures can be extracted +;; that is very very convenient + +(defun save-tree-data (tree-loc tree-table num-trees) + (with-open-file (stream "/usr/tmp/test-lisp-data.lisp" :direction :output) + (format stream "~S~%" tree-loc) + (format stream "~S~%" tree-table) + (format stream "~S~%" num-trees))) + +(save-tree-data "Tbilisi" '((45 redwood) (22 oak) (43 maple)) 110) + +(get-tree-data "/usr/tmp/test-lisp-data.lisp") + +;;; exercise - drawing graph of arbitrary function +(defun draw-y (y point) + (format t "~&") + (format t (concatenate 'string (make-string y :initial-element #\ ) point))) + +(defun make-graph () + (let ((requested-function (progn + (format t "~&Function to graph?") + (read))) + (start-value (progn + (format t "~&Starting x value?") + (read))) + (end-value (progn + (format t "~&Ending x value?") + (read))) + (plotting-string (progn + (format t "~&Plotting string?") + (read)))) + + (loop for x from start-value to end-value + do (draw-y (funcall requested-function x) plotting-string)))) + +(defun square (n) + (* n n)) +(square 7) + +(funcall #'square 4) + +(make-graph) + +;; yups + +(draw-y 5 "****") + +(concatenate 'string (make-string 10 :initial-element #\ ) ".") +(concatenate 'string "hello" " " "who") diff --git a/iteration-and-block-structure.lisp b/iteration-and-block-structure.lisp new file mode 100644 index 0000000..976ef38 --- /dev/null +++ b/iteration-and-block-structure.lisp @@ -0,0 +1,98 @@ +;; (dotimes (index-var n [result-form] +;; body) +;; +;; (dolist (index-var n [result-form] +;; body) +;; +;; result for is a thing to return, but is that joined from iterations? +(dotimes (x 5 `(list ,x)) + (format t "~&iterating ~S" x)) + +;; i guess that's from the last + +(dolist (x '(red blue green) 'x) + (format t "~&Roses are ~S" x) + (if (equal x 'blue) (return x))) + +;;; so [result-form] is returned if iteration reaches the end + +(assoc 'key1 '((key1 . value1) (key2 . "hello"))) +(assoc 'key1 '((key1 value1) (key2 "hello"))) + +;;; applicative squaring with mapcar are simpler +;;; for the iterative, first get local variable around list, and return statement reverse it +(defun it-square-list (x) + (let ((result nil)) + (dolist (i x (reverse result)) + (push (* i i) result)))) + +(it-square-list '(1 2 4 10)) + +;; the DO macro is "most powerful" iteration in CL + +;; (DO ((var1 init1 [update1]) +;; (var2 init2 [update2])) +;; (test action1 action2 ... action-n) +;; body) + +;; so, vars might not have update expressions +;; first assing vars, evaluate test, if test - to exit - evaluate end actions +;; if not test - evaluate body, then run updates to variables and repeat + +(defun launch (n) + (do ((cnt n (- cnt 1))) + ((zerop cnt) (format t "Blast off!~&")) + (format t "~S..." cnt))) + +(launch 10) +(launch 20) + +;; would be cool to find some kind of 2/3 dimentinal problem to be solved clearly with DO +;; like walking aroung the array + +;; also - body can have (return [value]) expressions! +;; so nil can be exit expression, for infinite iteration + +(defun read-a-number () + (do ((answer nil)) + (nil) + (format t "~&Please input a number: ") + (setf answer (read)) + (if (numberp answer) (return answer) + (format t "~&Sorry, ~S is not a number. Try again." answer)))) + +;;; Blocks. +;; implicit blocks are bodies of function, with function name being a block name +;; and RETURN-FROM can be used to exit block +;; DO, DOLIST, DOTIMES are wrapped with block with name nil, so RETURN is just RETURN-FROM nil +;; but we can to return from function, short circuiting + +(defun my-square-list (x) + (mapcar (lambda (i) + (if (numberp i) (* i i) + (return-from my-square-list `nope))) x)) + +(my-square-list '(1 2 51 4)) +(my-square-list '(1 3 5 "hello" 4)) + +;; and can create explicitly with BLOCK function? +;; and use RETURN-FROM from inside that block? what about from inside functions that are called in the block? + +(defun print-and-exit-my-block () + (format t "~&in the function") + (return-from my-block)) + +(block my-block + (format t "~&Entering my block") + (print-and-exit-my-block) ; gets error - unknown block, so YAY + (format t "~&After calling function in my block")) + +;;; Exercise +;;; about dna things + + + +;; progn, prog1, prog2 +;; prog1 returns value of first expression +;; prog2 -//- of second expression +;; progn -//- of last diff --git a/list-structure.lisp b/list-structure.lisp new file mode 100644 index 0000000..e0d4d35 --- /dev/null +++ b/list-structure.lisp @@ -0,0 +1,61 @@ +;;; missimetry of cons and bracketed list +(cons 16 (list 1 2 3)) +(cons (list 1 2 3) 5) + +;; so adding to front is easy, +;; adding to back is hard, since last element connected to nil + +(last `(1 2 3 4)) ; => (4) + +;; for sets: +;; member, union, intersection, set-difference, subsetp + +;; stopped at exercise 6.26 (i remember reading that in the court hallway) + +;;; tables / alists + +(setf words '((one un) + (two deu) + (three trois) + (four quatre) + (five cing))) + +(assoc 'three words) +(cdr '(one un)) +(rassoc '(un) words) ; why not found? + +(setf sounds '((cow . moo) + (pig . oink) + (cat . meow) + (dog . woof) + (bird . tweet))) + +(rassoc 'moo sounds) + +;;; keyword arguments... +(setf text `(b a n a n a - p a n d a)) +text + +(remove `a text) +(remove `a text :count 3) +(remove `a text :count 2 :from-end t) + +;; keyword is symbol with : at the start of the name +(keywordp ':hello) +(keywordp :hello) ; no need to quote? +(keywordp 'hello) + +;; trees, subst & sublis ? +;; performing substitutions from alist into tree (?) +;;; subst - substitute X for Y in Z +(subst 'the 'a '(a list even nested (a hare) will get a substitution)) + +;;; sublis - takes make substitutions at same time +;; and it takes which? alisp plist? urgh +;; in emacs - plist is one level list +;; alist - list of cons cells +;; here also 2 level list is alist, and what's expected +(sublis '((rose . red) (violet . blue) (sunflower . yellow)) + '(here is the rose strucure (another rose and violet thingy) multilevel)) + +;; I suppse could be used on "code as data" diff --git a/macro-and-compilartion.lisp b/macro-and-compilartion.lisp new file mode 100644 index 0000000..fc727c4 --- /dev/null +++ b/macro-and-compilartion.lisp @@ -0,0 +1,200 @@ + +(setf a 0) + +(incf a) + +(macroexpand-1 '(incf a)) + +(macroexpand-1 '(pop x)) + +(macroexpand-1 '(defstruct starship + (name nil) + (condition 'green))) + +(defmacro simple-incf (a) + (list 'setq a (list '+ a 1))) + +(simple-incf a) + +;;; difference with a function +(defun faulty-incf (a) + (setq a (+ a 1))) + +(faulty-incf a) + +;; for function call 'a is being evaluated to 10, and bound to a local variable +;; then we change value of that local variable, but external is not affected +;; +;; in macros, symbol a is not evaluated, and inserted into a lisp expression, +;; that ultimately changes value of the correct variable + +;;; backquote, allows for dequoting with , +`(hello ,a world! quoted (+ 10 1 2) unquoted ,(+ 10 1 2)) + +;; exercise +(defmacro set-mutual (a b) + `(progn + (setq ,a ',b) + (setq ,b ',a))) + +(set-mutual yo hei) +yo +hei + +(set-mutual val1 val2) + +(defun f (x y) + (showvar x) + (showvar y) + (* x y)) + +(defmacro showvar (x) + `(format t "~&Value of ~S is ~S" ',x ,x)) +(showvar yo) + +(f 15 4) + +;;; Splicing with backquote + +(setf name 'fred) +(setf address '(16 maple drive)) + +`(,name lives in ,address now) ; inserting +;; => (FRED LIVES IN (16 MAPLE DRIVE) NOW) + +`(,name lives in ,@address now) ; splicing +;; => (FRED LIVES IN 16 MAPLE DRIVE NOW) + +;; example of usage +(defmacro set-zero (&rest variables) + `(progn ,@(mapcar #'(lambda (var) + (list 'setf var 0)) + variables) + '(zeroed ,@variables))) + +(set-zero a b c d) + +(defmacro variable-chain (&rest variables) + `(progn ,@(mapcar #'(lambda (first second) + `(setq ,first ',second)) + variables + (rest variables)))) + +;; i even like my solution more thatn one in the book, with DO + +(variable-chain a b c d) + +(setf my-test-variables '(a b c d)) +(mapcar (lambda (first second) (setf first second)) + my-test-variables + (rest my-test-variables)) + +;;; Compilation +'(you can use #'compile and #'compile-file) + +(defun tedious-sqrt (n) + (dotimes (i n) + (if (> (* i i) n) (return i)))) + +(tedious-sqrt 17) +(time (tedious-sqrt 100000000000000000)) + +;;; &body lambda list keyword +(defmacro whille (test &body body) + `(do () + ((not ,test)) + ,@body)) + +(defvar i) +(setf i 0) +(whille (> 5 i) + (format t "~&calculating and mutating i = ~S" i) + (incf i)) + +;;; well, i had warning, but things actually worked. + +;; some editors treat &body differently +;; by specializing formatting / identing +;; and also signals to programmers intend, that's it's a lisp expresison + +;;; DESCTRUCTURING inputs to macro +(defmacro mix-and-match-1 (pair1 pair2) + (let ((x1 (first pair1)) + (y1 (second pair1)) + (x2 (first pair2)) + (y2 (second pair2))) + `(list '(,x1 ,y1) + '(,x1 ,y2) + '(,x2 ,y1) + '(,x2 ,y2)))) + +(mix-and-match-1 (fred wilma) (tony bony)) + +;; but, we coult treat arguments as lists where we define marco +(defmacro mix-and-match-2 ((x1 y1) (x2 y2)) + `(list '(,x1 ,y1) + '(,x1 ,y2) + '(,x2 ,y1) + '(,x2 ,y2))) + +(mix-and-match-2 (fred wilma) (tony bony)) + +;; and what would happen if it wasn't exact match with list of 2 elements? + +(mix-and-match-2 (fred wilma caddy) (tony bony)) +;; it fails with some check error + +;;; example in the book about macro DOVECTOR + +;;; So, what's that about Dynamic scoping & Lexical scoping? + +;; wow, i think I understand + +;; step 1: get two variables, one lexical - fished, one dynamic - birds +(setf fishes '(salmon trout)) + +(defvar birds) +(setf birds '(eagle parrot)) + +(defun show-fishes () + fishes) +(show-fishes) + +(defun show-birds () + birds) +(show-birds) + +(defun see-lexical-scoping (fishes) + `(local ,fishes and from #'show-fishes - ,(show-fishes))) + +(see-lexical-soping '(kilka akula)) + +(defun see-dynamic-scoping (birds) + `(local ,birds and from #'show-birds - ,(show-birds))) + +(see-dynamic-scoping '(sova dyatel)) +;; when I called #'show-birds from inside #'see-dynamic-scoping +;; it didn't go to the top level for value of 'birds +;; the value for 'birds was taken from previous "redefinition" +;; i.e any time we enter a funtion that defined dynamicly scoped variable +;; value of that variable, until we return from the funtion, is taken from it + +#'defvar ; when something could be assigned +#'defparameter ; settings, not assigned, to change reeval defparameter +#'defconstant ; should never change + +;;; use for special variable +*print-base* ; if we override it as parameter for our function + ; then FORMAT would pick up that value +(defun print-in-base (*print-base* x) + (format t "~&I'm printing ~D as ~S in base ~D" x x *print-base*)) +;; if I use ~S to print *print-base*, then 2 in base 2 is 10, 12 in base 12 is 10. lol + +(print-in-base 10 65) +(print-in-base 2 65) +(print-in-base 3 65) +(print-in-base 12 22) + +;; dynamic variable accepts changes from called functions, while scope that +;; rebound it is alive can be used to communicate information between parts of +;; system. that's quite complicated diff --git a/optional-arguments.lisp b/optional-arguments.lisp new file mode 100644 index 0000000..1b9b71b --- /dev/null +++ b/optional-arguments.lisp @@ -0,0 +1,59 @@ +;;; &optional (with and without default value) +;;; &rest +;;; &key (with or without default value) +;;; &aux - similar to LET* - additional variables, that can be calculated from other inputs, for example &rest +;;; +;; cool + +;; default argument +(defun lala-1 (x &optional y) + (format t "~&x value is ~S" x) + (format t "~&y value is ~S" y) + (list x y)) + +(lala-1 2 5) +(lala-1 7) + +(defun lala-2 (x &optional (y 2)) + (format t "~&x value is ~S" x) + (format t "~&y value is ~S" y) + (list x y)) + +(lala-2 1 5) +(lala-2 7) + +;; rest arguments - accessed as list, unlimited number on call +(defun lala-3 (x y &rest args) + (append (list x y) args)) + +(lala-3 7 5 1 2 34 5 6) + +;;; keyword arguments +(defun make-sundae (name &key (ice-cream `vanilla) + (syrup `chocolate) + nuts + cherries + whipped-cream) + (list 'sundae + (list 'for name) + (list ice-cream 'with syrup 'sypup) + (list 'toppings '= + (remove nil + (list (and nuts 'nuts) + (and cherries 'cherries) + (and whipped-cream 'whipped-cream)))))) + +(make-sundae 'yo) +(make-sundae 'yo + :syrup 'maple + :whipped-cream t) + +;;; auxillary variables +;; &aux - additional local variables? +;; "a matter of taste, whether to use LET* around body or &aux attributes" + +(defun my-average (&rest args + &aux (len (length args))) + (/ (reduce #'+ args) len)) + +(my-average 1 2 3 4 5 6) diff --git a/packages.lisp b/packages.lisp new file mode 100644 index 0000000..aef4a20 --- /dev/null +++ b/packages.lisp @@ -0,0 +1,16 @@ +;; https://www.tutorialspoint.com/lisp/lisp_packages.htm +;; +;; how do I check in which package I'm by default / right now? +;; it's stored in variable +;; +;; (in-package "COMMON-LISP-USER") => # + ;; (package-name *package*) => "COMMON-LISP-USER" + ;; +;; how did I find it? I called sly-documentation-lookup (C-c C-d C-h) +;; and searched for package, and http://www.lispworks.com/documentation/HyperSpec/Body/f_pkg_na.htm +;; had examples! + +*package* +(package-name *package*) + +;; yay! diff --git a/quicklisp-thing.lisp b/quicklisp-thing.lisp new file mode 100644 index 0000000..fdb9a71 --- /dev/null +++ b/quicklisp-thing.lisp @@ -0,0 +1,66 @@ + +;; that's for initial installation +;; (load "~/Downloads/quicklisp.lisp") + +;; that prints into repl - +;; (quicklisp-quickstart:help) and (quicklisp-quickstart:install) are paths forward +;; would I maybe want to install it with nix? +;; +;; I could try +;; I guess it works, there's binary and /lib in ~/.nix-profille +;; /home/efim/.nix-profile/lib/common-lisp/quicklisp/setup.lisp + +;; so, "loading after installation" from https://www.quicklisp.org/beta/#loading +;; is what I'd want + +;; (load "~/.nix-profile/lib/common-lisp/quicklisp/setup.lisp") +;; error! "Can't create directory", welp +;; then how would I load it? +;; do I need to modify sbcl startup? +;; sbcl is also installed with nix, so it could probably integrate loading of quicklisp? + +;;; welp, I've asked a question on discourse +;; maybe somebody will help, and then I'd document this +;; https://discourse.nixos.org/t/how-to-use-quicklisp-with-sbcl/20539 + +;; I'll proceed with manual installation +;; https://www.quicklisp.org/beta/#loading + +;; well, that seems to work. with manual step of adding to ~/.sblcrc +;; now restarting sly I have quicklisp +;; I guess that's ok + +;;; Now, how to use it? +;; one commad is already present in installation guide +(ql:system-apropos "vecto") +(ql:system-apropos "matrix") +(ql:system-apropos "cells") + +;; and there's +#'ql:quickload + +;; and counterpart +#'ql:uninstall + +;; this is of course absolutely not pure or nixy +;; ok, now, I just go about reading on the packages themselves, and there's not much on the quicklisp? +;; maybe + +;;; could look into "awesome-cl" list +;; maybe I'd find something to play with +;; https://github.com/CodyReichert/awesome-cl + +;;; ?? what is "in-package"? +(ql:quickload "fset") + +(in-package fset-user) +(isetq s (map ('a 2) :default 1)) + + +(in-package cl-user) +(isetq s (map ('a 2) :default 1)) ; error, yay + +;; promising things to look at are +;; cl21 http://cl21.org/ +;; Alexandria +;; FSet https://fset.common-lisp.dev/Site/FSet-Tutorial.html diff --git a/recursion.lisp b/recursion.lisp new file mode 100644 index 0000000..f4293eb --- /dev/null +++ b/recursion.lisp @@ -0,0 +1,100 @@ + +(null 'a) +(null ()) +(null nil) + +(defun anyoddp (x) + (cond ((null x) nil) + ((odd (first x)) t) + (t (anyoddp (rest x))))) + +(trace anyoddp) +(anyoddp (list 6 1)) +(untrace) +(rest '(5 4 3 2 1)) + +;;; my error was - function wasn't named odd, it was oddp +;;; and in the debugger it looked like: +;;; ("undefined function" 6) +;;; and I thought that 6 was treated as undefined function in list (6 1) for some reason + +(defun laugh (n) + (defun laugh-inner (n acc) + (cond ((eq 0 n) acc) + (t (laugh-inner (- n 1) (cons 'HA acc ))))) + (laugh-inner n ())) + +;; I tried to use append +;; but how the hell do I add elements to list? +;; do I just fucking manually create cons? ugh +(cons 1 '(4 5 6)) + +(laugh 4) + +(defun square-list (x) + (cond ((null x) ()) + (t (cons (* (first x) (first x)) + (square-list (rest x)))))) + +(square-list '(1 3 5 6)) + +;;; count atoms. +;;; recursion on nested lists - think of them as binary trees, with car and cdr, that's it + +(atom 1) + +(defun count-atoms (tree) + (cond + ((null tree) 0) ; without that ends of lists would be counted, but didn't include that due to misunderstanding + ((atom tree) 1) + (t (+ (count-atoms (car tree)) + (count-atoms (cdr tree)))))) + +(count-atoms '(1 (4 5) 2 )) + +(defun pairings (x y) + (cond ((or (null x) (null y)) ()) + (t (cons (list (first x) (first y)) + (pairings (rest x) (rest y)))))) + +(pairings '(1 2 3 7) '(a b c d)) + +;;; looking into debugger +(defun my-fact (n) + (cond ((zerop n) (break "N is zero") + ;; 1 + ) + (t (* n (my-fact (- n 1)))))) + +(my-fact 4) + +;;; So - debugger keys and functions +;; C-j and C-k are for moving between frames +;; for frame context commands R - return from frame with particular value (sly-db-return-from-frame) +;; x - step over, s - step +;; e - eval in frame, i - inspect in frame (show additional info on evaluated value) +;; RET - toggle details for current frame +;; v - show frames code +;; d - pretty-print-eval-in-frame +;; (searching all of functions by going into debugger bugger and looking at *helpful* (C-h C-f) "sly-db-" + +;; could also try to recompile thing, maybe r for restart, or R to return with value 1 from last frame and check how it all works + +;;; better way to define inner functions : LABELS +;;; similar to LET form, binding names to arglists and body +;;; they are "local functions" +;;; can call each other, and reference parent variables + +(defun factor-tree (n) + (factors-help n 2)) + +(defun factors-help (n p) + (cond + ((equal p n) n) + ((zerop (rem n p)) (list n p (factors-help (/ n p) p))) + (t (factors-help n (+ 1 p))))) + +(factor-tree 60) + +(trace factors-help) +(untrace) ; and there's no need to try to do println, and less errors in that diff --git a/session1.log b/session1.log new file mode 100644 index 0000000..e69de29 diff --git a/structures-and-type-system.lisp b/structures-and-type-system.lisp new file mode 100644 index 0000000..e6ec793 --- /dev/null +++ b/structures-and-type-system.lisp @@ -0,0 +1,116 @@ + +;; chapter 12, not covering CLOS + +(defstruct starship + (name nil) + (speed 0) + (condition `green) + (shields `down)) + +;; this defines also a MAKE-STARSHIP +;; and also STARSHIP becomes type that works with TYPEP and TYPE-OF, and type predicate STARSHIP-P + +(setf s1 (make-starship)) +s1 + +(setf s2 '#s(starship speed (warp 3) + condition red + shields up)) +s2 + +(type-of s2) + +;; also there are accessor functions: +(starship-shields s2) +(starship-speed s2) + +;; and they can be used for SETF as place functions, cool +(setf (starship-name s1) "Enterprise") +s1 + +;;; and the constructor also takes arguments as &keys +(setf s3 (make-starship :name "Reliant" + :shields 'damaged)) + +(describe s3) + +;;; exercise, discrimination net +(defstruct node + name + question + yes-case + no-case) + +(setf *NODE-LIST* nil) + +(defun init () + (setf *node-list* nil)) +(init) + +(defun add-node (name question yes-case no-case) + (push (make-node :name name + :question question + :yes-case yes-case + :no-case no-case) + *node-list*)) + + +(add-node 'other + "Bad question?" + "Hello, yesman" + "Goodbye, noman") + +(add-node 'start + "Does the engine turn over?" + 'engine-turns-over + 'engine-wont-turn-over) + +(add-node 'engine-turns-over + "lalal?" + "yes, lala" + "no, alallala") + +*node-list* + +(defun find-node (name nodes) + (find name nodes :test (lambda (left right) (equal (node-name right) left)))) +;; so in :test function, first item is the one we're searching for +;; and right one is the one we iterate over + +(find-node 'start *node-list*) +(find-node 'other *node-list*) +(find-node 'engine-turns-over *node-list*) + +;; either print that node not defined +;; or ask question and return action +(defun process-node (name) + (let ((current-node (find-node name *node-list*))) + (if current-node + (progn + (format t "~&~S" (node-question current-node)) + (if (yes-or-no-p) (node-yes-case current-node) + (node-no-case current-node))) + (format t "~&No node is defined")))) + +(process-node 'start) +(process-node 'engine-turns-over) +(process-node 'end) + + +;; on 'start' node +;; loop asking question, and processing response +;; if node - find and continue running +;; if string - print +(defun run (node-list) + (do ((current-block 'start (process-node current-block))) + (nil) + ( if (stringp current-block) + (format t "~S" current-block)) + (if (or (stringp current-block) + (null current-block)) + (return)))) + +(process-node 'start) +(process-node 'engine-turns-over) + +(run *node-list*) diff --git a/test-input.lisp b/test-input.lisp new file mode 100644 index 0000000..a7c8259 --- /dev/null +++ b/test-input.lisp @@ -0,0 +1,3 @@ +"The North Slope" +((45 redwood) (12 oak) (43 maple)) +100 diff --git a/toolkit.lisp b/toolkit.lisp new file mode 100644 index 0000000..0a53254 --- /dev/null +++ b/toolkit.lisp @@ -0,0 +1,22 @@ + + +;;; TIME +;; it's profiling of evaluation +(defun addup (n) + (do ((i 0 (+ 1 i)) + (sum 0 (+ sum i))) + ((> i n) sum))) + +(time (addup 10)) ; prints into repl +(time (addup 1000000)) +(time (addup 10000000)) + + +;;; DESCRIBE and INSPECT +(describe #'cons) ; prints into repl, same as K +lookup/documentation + +;; INSPECT - is interactive +;; H - for help +;; U - for UP, Q/E - to exit +;; numbers - to dig into slots of a structure + diff --git a/trace-and-dtrace.lisp b/trace-and-dtrace.lisp new file mode 100644 index 0000000..ead3310 --- /dev/null +++ b/trace-and-dtrace.lisp @@ -0,0 +1,13 @@ + +(defun half (n) (* n 0.5)) + +(defun average (x y) + (half (+ x y))) + +(trace) ; returns list of traced functions +(trace half average) + +(average 7 5) ; tree of calls printed into repl + +(untrace half) +(untrace) ; untraces all diff --git a/vars-and-effects.lisp b/vars-and-effects.lisp new file mode 100644 index 0000000..76d7053 --- /dev/null +++ b/vars-and-effects.lisp @@ -0,0 +1,94 @@ +;; setq defvar defun - examples of sideffectful things + +(random 100) + +;; setq could even change local variables (defined by function arguments) +(defun bad-style (p) + "This function will overdefine it's input P." + (setf p (+ p 2)) ; changes local variable + (setf r (* p 2)) + `(result is ,p)) + +p ; this is not set by the setf +r ; this global value is changed + +(bad-style 15) + +;; wait, there's setf, what's different in setq? +;; setf has "place" as first item, so setter forms + +(documentation `setf `function) +(documentation `setq `function) + +(apropos "random") + +;;; exercises + +(defun throw-die () + (+ 1 (random 6))) +(throw-die) + +(defun throw-dice () + (list (throw-die) (throw-die))) +(throw-dice) + +(defun snake-eyes-p (thro) + (equal thro `(1 1))) +(snake-eyes-p `(1 1)) +(snake-eyes-p `(1 2)) + +(defun boxcars-p (thro) + (equal thro `(6 6))) +(boxcars-p `(6 6)) +(boxcars-p `(1 2)) + +(funcall `+ `(1 2)) ; 149 +(apply `+ `(1 2 5)) + +(defun instant-win-p (the-throw) + (let ((win-hands `(7 11)) + (sum (apply #'+ the-throw))) + (member sum win-hands))) + +(defun instant-loss-p (the-throw) + (let ((loose-hands `(2 3 12)) + (sum (apply #'+ the-throw))) + (member sum loose-hands))) +;;; breaking my head, looking for #'contains function for list +;;; apropos doesn't quite help +(member 7 (list 1 4 7 11)) ; well, member returns "rest" + +(instant-win-p `(6 5)) ; so, this is correct. cool +(or `t nil) + +(instant-loss-p `(6 5)) + +(defun say-throw (the-throw) + (cond ((equal the-throw `(1 1)) `snake-eyes) + ((equal the-throw `(6 6)) `boxcars) + (t (apply #'+ the-throw)))) +(say-throw '(1 1)) +(say-throw '(6 6)) +(say-throw '(2 5)) + +;; firsth throw either insta-win, insta-loose, or set point +(defun craps () + (let* ((the-throw (throw-dice )) + (result (cond ((instant-loss-p the-throw) `(,(say-throw the-throw) -- you loose)) + ((instant-win-p the-throw) `(,(say-throw the-throw) -- you win)) + (t `(your point is ,(say-throw the-throw)))))) + (append `(throw ,(first the-throw) and ,(second the-throw) -- ) result))) + +(craps) + +(defun try-for-point (point) + (let* ((the-throw (throw-dice)) + (value (apply #'+ the-throw)) + (result (cond ((equal value point) `(you win)) + ((equal value 7) `(you loose)) + (t `(throw again))))) + (append `(throw ,(first the-throw) and ,(second the-throw) -- ,value --) result))) + +(try-for-point 8) + +;; next onto the 6, list data structures