;;; This is an easy one: using MAPCAR to ;;; _return_ a list of all the keys in an ALIST USER(8): (defun all-keys (alist) (mapcar 'assoc-key alist)) ALL-KEYS USER(9): (all-keys *fruit-colors*) (APPLE BANANA PEPPER BLUEBERRY CHERRY) ;;; We can still use MAPCAR to print all the ;;; pairs in the ALIST USER(10): (defun print-all-pairs (alist) (mapcar #'(lambda (assoc) (format t "~a -> ~a~%" (assoc-key assoc) (assoc-values assoc))) alist)) PRINT-ALL-PAIRS ;;; This works, but notice the return value: it ;;; is 5 calls to FORMAT, each of which returns NIL. USER(11): (print-all-pairs *fruit-colors*) APPLE -> (RED GREEN) BANANA -> (YELLOW) PEPPER -> (RED GREEN YELLOW) BLUEBERRY -> (PURPLE) CHERRY -> (RED WHITE) (NIL NIL NIL NIL NIL) ;;; A preferable way is to use MAPC, because it ;;; says you are doing the function for side ;;; effects. USER(12): (defun print-all-pairs (alist) (mapc #'(lambda (assoc) (format t "~a -> ~a~%" (assoc-key assoc) (assoc-values assoc))) alist)) PRINT-ALL-PAIRS USER(13): (print-all-pairs *fruit-colors*) APPLE -> (RED GREEN) BANANA -> (YELLOW) PEPPER -> (RED GREEN YELLOW) BLUEBERRY -> (PURPLE) CHERRY -> (RED WHITE) (#S(ASSOC :KEY APPLE :VALUES (RED GREEN)) #S(ASSOC :KEY BANANA :VALUES (YELLOW)) #S(ASSOC :KEY PEPPER :VALUES (RED GREEN YELLOW)) #S(...) ...) ;;; Next problem is to print a numbered list of the ;;; associations. First version uses MAPC, which is ;;; fine. USER(14): (defun print-numbered-list (alist) (let ((i 1)) (mapc #'(lambda (assoc) (format t "~a. ~a -> ~a~%" i (assoc-key assoc) (assoc-values assoc)) (incf i)) alist))) PRINT-NUMBERED-LIST USER(15): (print-numbered-list *fruit-colors*) 1. APPLE -> (RED GREEN) 2. BANANA -> (YELLOW) 3. PEPPER -> (RED GREEN YELLOW) 4. BLUEBERRY -> (PURPLE) 5. CHERRY -> (RED WHITE) (#S(ASSOC :KEY APPLE :VALUES (RED GREEN)) #S(ASSOC :KEY BANANA :VALUES (YELLOW)) #S(ASSOC :KEY PEPPER :VALUES (RED GREEN YELLOW)) #S(...) ...) ;;; An alternative is DOLIST, which allows us to iterate ;;; through the list easily. USER(16): (defun print-numbered-list (alist) (let ((i 1)) (dolist (assoc alist) (format t "~a. ~a -> ~a~%" i (assoc-key assoc) (assoc-values assoc)) (incf i)))) PRINT-NUMBERED-LIST USER(17): (print-numbered-list *fruit-colors*) 1. APPLE -> (RED GREEN) 2. BANANA -> (YELLOW) 3. PEPPER -> (RED GREEN YELLOW) 4. BLUEBERRY -> (PURPLE) 5. CHERRY -> (RED WHITE) NIL ;;; Here we do it by iterating over numeric values ;;; of I. This is a _very_ inefficient function in ;;; that it has to traverse the list once to get its ;;; length, then once more every iteration through the ;;; list to get the Ith element. USER(18): (defun print-numbered-list (alist) (dotimes (i (length alist)) (let ((assoc (elt alist i))) (format t "~a. ~a -> ~a~%" i (assoc-key assoc) (assoc-values assoc))))) PRINT-NUMBERED-LIST USER(19): (print-numbered-list *fruit-colors*) 0. APPLE -> (RED GREEN) 1. BANANA -> (YELLOW) 2. PEPPER -> (RED GREEN YELLOW) 3. BLUEBERRY -> (PURPLE) 4. CHERRY -> (RED WHITE) NIL ;;; This is a more general iterator: here we ;;; can iterate over two lists in parallel. USER(20): (defun print-numbered-list (alist) (do ((local-list alist (cdr local-list)) (i 1 (+ i 1))) ((null local-list) NIL) (format t "~a. ~a -> ~a~%" i (assoc-key (first local-list)) (assoc-values (first local-list))))) PRINT-NUMBERED-LIST USER(21): (print-numbered-list *fruit-colors*) 1. APPLE -> (RED GREEN) 2. BANANA -> (YELLOW) 3. PEPPER -> (RED GREEN YELLOW) 4. BLUEBERRY -> (PURPLE) 5. CHERRY -> (RED WHITE) NIL ;;; Here we started talking about implementing cash cards. ;;; We began by setting up a very simple data structure ;;; for accounts. For the cash cards, all we need is an ;;; account balance. Here we define the structure and ;;; create one to play with. USER(22): (defstruct account balance) ACCOUNT USER(23): (setf aa (make-account :balance 20)) #S(ACCOUNT :BALANCE 20) USER(24): (defun make-cash-card (account limit &key (debit-on-creation-p NIL)) (let ((debit-on-transaction-p (not debit-on-creation-p))) (cond ((and debit-on-creation-p (> limit (account-balance account))) NIL) (T (when debit-on-creation-p (decf (account-balance account) limit)) #'(lambda (amount) (cond ((or (> amount limit) (and debit-on-transaction-p (> amount (account-balance account)))) NIL) (T (decf limit amount) (when debit-on-transaction-p (decf (account-balance account) amount)) T))))))) MAKE-CASH-CARD ;;; This is a bizarre looking return result, but ;;; we figured out it was a function. USER(27): (setf cc (make-cash-card aa 100)) # ;;; And if it's a function, we can call it. The return ;;; result of T tells us that it was OK to withdraw 10 dollars ;;; from account aa. USER(28): (funcall cc 10) T ;;; And magically, aa's balance has gone from 20 to 10! USER(29): (account-balance aa) 10