exercises and notes from "Gentle introduction"
This commit is contained in:
commit
067aebaf81
|
@ -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
|
|
@ -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))
|
|
@ -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!
|
|
@ -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
|
|
@ -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)
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
(defun hello ()
|
||||||
|
(write-line "What is your name?")
|
||||||
|
(let ((name (read-line)))
|
||||||
|
(format t "Hello, ~A.~%" name)))
|
|
@ -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")
|
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -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)
|
|
@ -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 "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!
|
|
@ -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
|
|
@ -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
|
|
@ -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*)
|
|
@ -0,0 +1,3 @@
|
||||||
|
"The North Slope"
|
||||||
|
((45 redwood) (12 oak) (43 maple))
|
||||||
|
100
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue