;;; Create a dummy account data type and instance USER(6): (defstruct account balance) ACCOUNT USER(7): (setf dummy-account (make-account :balance 100)) #S(ACCOUNT :BALANCE 100) ;;; Make a cash card USER(8): (setf dummy-card (make-cash-card dummy-account 50)) # ;;; And call it: now its limit is 40 and the account should ;;; should have 90 USER(10): (funcall dummy-card 10) T USER(11): (account-balance dummy-account) 90 ;;; This is over the limit USER(12): (funcall dummy-card 50) NIL ;;; Here is another closure pointing to the same account USER(14): (setf another-card (make-cash-card dummy-account 10)) # USER(16): dummy-card # USER(17): another-card # ;;; We run the balance of the other card down to 0 USER(18): (funcall another-card 10) T USER(19): (funcall another-card 10) NIL ;;; The point here is that the balance of the account ;;; was decremented by both cards, but the variable ;;; LIMIT was not shared by them. USER(20): (account-balance dummy-account) 80 ;;; Here is an example where a closure can keep ;;; track of a location in a list for you, without ;;; actually giving you direct access to a pointer ;;; into the list. Notice that THE-ASSOC is ;;; bound only once, when the function is defined. ;;; Therefore the call to FIND-ASSOC, which might ;;; take a long time, only needs to be done once. USER(21): (defun fruit-colors (fruit-name) (let ((the-assoc (find-assoc fruit-name))) (cond ((null the-assoc) #'(lambda () NIL)) (T #'(lambda () (assoc-values the-assoc)))))) FRUIT-COLORS ;;; Now when we call the function, we get back a ;;; closure that will return the current association ;;; value each time it is called, but without searching ;;; the assoc list. USER(22): (setf apple-finder (fruit-colors 'apple)) # USER(24): (funcall apple-finder) (RED GREEN) ;;; Now we side-effect the list USER(25): (add-value 'apple 'orange) (ORANGE RED GREEN) ;;; And we see the new version USER(26): (funcall apple-finder) (ORANGE RED GREEN) ;;; This is a very broken way to return the value 3: ;;; define an anonymous function that returns 3, and ;;; call it. The anonymous function will immediately ;;; be garbage collected. USER(29): (defun return-3 () (funcall #'(lambda () 3))) RETURN-3 USER(31): (return-3) 3 ;;; This is a version of the same function that returns ;;; two values: a success indicator (was the association ;;; founc), and the closure. USER(34): (defun fruit-colors (fruit-name) (let ((the-assoc (find-assoc fruit-name))) (cond ((null the-assoc) (values NIL #'(lambda () NIL))) (T (values T #'(lambda () (assoc-values the-assoc))))))) FRUIT-COLORS ;;; Here notice that two values are being returned USER(35): (fruit-colors 'grape) NIL # USER(36): (fruit-colors 'apple) T # ;;; Here is how we "catch" the two values. This creates ;;; global bindings for both SUCCESS and CLOSURE. USER(38): (multiple-value-setq (success closure) (fruit-colors 'apple)) T USER(39): success T USER(40): closure # USER(41): (funcall closure) (ORANGE RED GREEN) ;;; This would be the equivalent code if FRUIT-COLORS ;;; returned a list of two values instead of returning ;;; two values directly. USER(42): (let* ((return-list (fruit-colors 'apple)) (success (first return-list)) (closure (second return-list))) ) Error: Attempt to take the car of T which is not a cons. [condition type: SIMPLE-ERROR] ;;; This is how you intercept mutliple values but uses ;;; _lexical_ rather than global variables. Here S and ;;; C are bound only within the MULTIPLE-VALUE-BIND form. USER(44): (multiple-value-bind (s c) (fruit-colors 'grape) (funcall c)) NIL USER(45): (multiple-value-bind (s c) (fruit-colors 'apple) (funcall c)) (ORANGE RED GREEN) USER(46): s Error: Attempt to take the value of the unbound variable `S'. [condition type: UNBOUND-VARIABLE] [1] USER(47): c Error: Attempt to take the value of the unbound variable `C'. [condition type: UNBOUND-VARIABLE]