;;; Random bits & pieces of LISP. ;; First, the PROGN. Its value is the last expression evaluated---and ;; this is already cheating, because why are we ignoring the intermediate ;; values? Clearly, we do this for their side-effects, like SETQ or SETF. ;; This already makes our program impure, and much harder to analyze. ;; DEFUN is actually a macro. It uses PROGN for a side-effect: setting ;; the DEFUN-ed symbol to the function body. This is major cheating; ;; for example, it allows us to call a function before defining of ;; that function's body is properly finished. However, as the ;; Y-combinator shows, we don't actually need this cheat to effect ;; recursion---it can be implemented with LAMBDAs alone. >(MACROEXPAND '(defun foo (x) (+ 1 x))) (PROGN (SETF (SYMBOL-FUNCTION 'FOO) #'(LAMBDA (X) (BLOCK FOO (+ 1 X)))) 'FOO) T ;; DEFUN, of course, is a special form. In GCL, it's easy to ascertain ;; this for a symbol, by using HELP: >(help 'defun) ----------------------------------------------------------------------------- DEFUN [Special form and Macro] (not found "gcl.info") From ((DEFUN . Special Forms and Functions) gcl-si.info): -- Special Form: DEFUN ^^^^^^^^^^^^^^^^^^^ Package:LISP Syntax: (defun name lambda-list {decl | doc}* {form}*) Defines a function as the global function definition of the symbol NAME. The complete syntax of a lambda-list is: ({var}* [&optional {var | (var [initform [svar]])}*] [&rest var] [&key {var | ({var | (keyword var)} [initform [svar]])}* [&allow-other-keys]] [&aux {var | (var [initform])}*]) The doc-string DOC, if supplied, is saved as a FUNCTION doc and can be retrieved by (documentation 'NAME 'function). ----------------------------------------------------------------------------- ;; What does DEFUN set? It's actually a separate slot in the symbol whose name ;; is supplied to DEFUN. This slot is called symbol-function or "function value" ;; of a symbol. ;; A Common Lisp implementation of a symbol has 5 slots for various values associated ;; with it. These slots can be queried: >(SYMBOL- SYMBOL-FUNCTION SYMBOL-NAME SYMBOL-PACKAGE SYMBOL-PLIST SYMBOL-VALUE ;; The two most important slots are the symbol-value and symbol-function. The former ;; is what a symbol evaluates to as an _argument_ in a function call. The latter ;; is extracted and applied when the symbol appears first in an evaluated list ;; (i.e., as the name of the function called). ;; The bindings of these slots can be tested with BOUNDP and FBOUNDP respectively. ;; Note that a symbol may exist but have neither value actually bound to it: >(FIND-SYMBOL "FOO") FOO :INTERNAL >(BOUNDP 'foo) NIL >foo Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by EVAL. Condition in EVAL [or a callee]: INTERNAL-SIMPLE-UNBOUND-VARIABLE: Cell error on FOO: Unbound variable: Broken at EVAL. Type :H for Help. 1 Return to top level. >>1 Top level. >(FBOUNDP 'foo) NIL ;; SYMBOL-FUNCTION extracts the function slot _if it's been bound_, otherwise results in an error: >(SYMBOL-FUNCTION 'foo) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SYMBOL-FUNCTION. Condition in SYMBOL-FUNCTION [or a callee]: INTERNAL-SIMPLE-UNDEFINED-FUNCTION: Cell error on FOO: Undefined function: Broken at SYMBOL-FUNCTION. Type :H for Help. 1 Return to top level. >>1 ;; SYMBOL-VALUE extracts the symbol's value _if it's been bound_, otherwise results in an error: Top level. >(SYMBOL-VALUE 'foo) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SYMBOL-VALUE. Condition in SYMBOL-VALUE [or a callee]: INTERNAL-SIMPLE-UNBOUND-VARIABLE: Cell error on FOO: Unbound variable: Broken at SYMBOL-VALUE. Type :H for Help. 1 Return to top level. >>1 Top level. >(HELP 'SYMBOL-VALUE) ----------------------------------------------------------------------------- SYMBOL-VALUE [Function] ----------------------------------------------------------------------------- SYMBOL-VALUE [Setf] Defined as: (DEFSETF SYMBOL-VALUE SET) See the doc of DEFSETF.(not found "gcl.info") From ((SYMBOL-VALUE . Symbols) gcl-si.info): -- Function: SYMBOL-VALUE (symbol) Package:LISP Returns the current value of the dynamic (special) variable named by SYMBOL. ----------------------------------------------------------------------------- ;; Since the value and the function bound to a symbol are completely orthogonal, ;; it's possible to call that function on that value with (FOO FOO): >(defun foo (x) (+ 1 x)) FOO >(FBOUNDP 'foo) T >(SYMBOL-FUNCTION 'foo) (LAMBDA-BLOCK FOO (X) (+ 1 X)) ;; But FOO is still unbound as a symbol---that slot is still "nothing": >(BOUNDP 'foo) NIL >foo Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by EVAL. Condition in EVAL [or a callee]: INTERNAL-SIMPLE-UNBOUND-VARIABLE: Cell error on FOO: Unbound variable: Broken at EVAL. Type :H for Help. 1 Return to top level. >>1 Top level. ;; Let's set it: >(setq foo 100) 100 ;; And now we can call the function_value bound to FOO on the value bound to FOO: >(foo foo) 101 ;; We can extract the function_value of FOO for an argument, too, but of course that ;; will not evaluate right, because adding 1 to a LAMBDA is not defined: >(foo #'foo) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by +. Condition in + [or a callee]: INTERNAL-SIMPLE-TYPE-ERROR: (LAMBDA-BLOCK FOO (X) ...) is not of type NUMBER: Broken at +. Type :H for Help. 1 Return to top level. >>1 Top level. ;; But we can use that function_value in a FUNCALL: (funcall #'foo foo) 101 ;;;------- more examples of LAMBDAs: ------- >(mapcar (lambda (y) (list y)) '(a b c d)) ((A) (B) (C) (D)) ;;;----------- Let's explore lexical binding/closures: ----------- ;;; (try the same in an Emacs buffer under the default dynamic ;;; scoping to see the difference!) >(defun make-adder (n) #'(lambda (x) (+ x n))) MAKE-ADDER >(make-adder 2) (LAMBDA-CLOSURE ((N 2)) () ((MAKE-ADDER BLOCK #<@0000000103C90510>)) (X) (+ X N)) >(setq add2 (make-adder 2)) (LAMBDA-CLOSURE ((N 2)) () ((MAKE-ADDER BLOCK #<@0000000103C901D0>)) (X) (+ X N)) >add2 (LAMBDA-CLOSURE ((N 2)) () ((MAKE-ADDER BLOCK #<@0000000103C901D0>)) (X) (+ X N)) >(funcall add2 10) 12 >(funcall add2 550) 552 >(setq add1000 (make-adder 1000)) (LAMBDA-CLOSURE ((N 1000)) () ((MAKE-ADDER BLOCK #<@0000000103C8DEC0>)) (X) (+ X N)) ;; This will not work, because add1000 has its symbol-value slot set by the above, ;; not its symbol-function slot (unlike how a DEFUN would set it): >(add1000 1) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by EVAL. Condition in EVAL [or a callee]: INTERNAL-SIMPLE-UNDEFINED-FUNCTION: Cell error on ADD1000: Undefined function: Broken at EVAL. Type :H for Help. 1 Return to top level. >>1 Top level. ;; So we need FUNCALL to use that LAMBDA result of MAKE-ADDER: >(funcall add1000 1) 1001 >(funcall add1000 20) 1020 ;; Let's now create a closure with *mutable* internal state: >(defun make-adderb (n) #'(lambda (x &optional change) (if change (setq n x) (+ x n)))) MAKE-ADDERB >(setq add1 (make-adderb 1)) (LAMBDA-CLOSURE ((N 1)) () ((MAKE-ADDERB BLOCK #<@0000000103C829D0>)) (X &OPTIONAL CHANGE) (IF CHANGE (SETQ N X) (+ X N))) >(funcall add1 100) 101 ;; We can now change that state: >(funcall add1 10 t) 10 >(funcall add1 5) 15