// // This transcript---errors and all---is what we saw in class today. // // The LISP interpreter is GCL, GNU Common Lisp. I installed it // via MacPorts with "port install gcl". GCL supports tab-completion // of standard symbol names, the help function for online help, // and nice command-line editing (via the classic Unix Readline library // that lets you scroll through history, search it for prior commands // with Ctrl+r and so on). I like it for these reasons, but there // are other nice alternatives available through MacPorts: e.g., CLISP // ("port install clisp"). There are other implementations available, // too, like SBCL---you may end up using them if you choose a LISP-based // project where a major library requires a specific feature or flavor. // Remember, ' in front of an expression, the same as (quote ), // means, "don't evaluate me, pass me to the function as you built me // as you parsed me, in the 'Read' part of the Read-Eval-Print Loop (REPL)". firefly:~ user$ gcl GCL (GNU Common Lisp) 2.6.12 ANSI Nov 27 2014 05:23:43 Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl) Binary License: GPL due to GPL'ed components: (READLINE UNEXEC) Modifications of this banner must retain notice of a compatible license Dedicated to the memory of W. Schelter // Tab completion! >(C Display all 118 possibilities? (y or n) // More tab completion, this time the prefix is uncommon enough to get only a few possible completions: >(SYMBOL- SYMBOL-FUNCTION SYMBOL-NAME SYMBOL-PACKAGE SYMBOL-PLIST SYMBOL-VALUE // And online help is here too: >(help 'load) ----------------------------------------------------------------------------- LOAD [Function] (not found "gcl.info") From ((LOAD . Streams and Reading) gcl-si.info): -- Function: LOAD (filename &key (verbose *load-verbose*) (print nil) (if-does-not-exist :error)) Package:LISP Loads the file named by FILENAME into GCL. ----------------------------------------------------------------------------- >(+ 1 2) 3 // Let's create a list! >(list 3 6 3 89 65 2344) (3 6 3 89 65 2344) >(sort '(list 3 6 3 89 65 2344)) // Oops, SORT needs a function to compare the list elements as a second argument. // Also, the quote should not be there---I mistyped. Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SORT. Condition in SORT [or a callee]: INTERNAL-SIMPLE-PROGRAM-ERROR: SORT [or a callee] requires more than one argument. // The debugger has its own environment, with a rich set of commands (listed by :h). To be honest, // I never used its full power---even when I wrote large LISP symbolic computation programs; // since LISP allows you to write, test, and debug code in small pieces, debugging was never // the kind of a puzzle it often is in C. Broken at SORT. Type :H for Help. 1 Return to top level. >>1 Top level. // Argh, another typo: since I typed the quote, the symbol LIST is actually // the first element of the list I am trying to sort! Not being a number, // the comparison function < fails on it. >(sort '(list 3 6 3 89 65 2344) '<) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SORT. Condition in SORT [or a callee]: INTERNAL-SIMPLE-TYPE-ERROR: LIST is not of type REAL: Broken at SORT. Type :H for Help. 1 Return to top level. >>1 Top level. // I am still not noticing the stupid quote---and, being puzzled, tried // passing the comparator function---which I thought was the problem---as // its compiled implementation, #'< But that's not what I typed :) // I typed '#<, which is non-sensical, and created another error: >(sort '(list 3 6 3 89 65 2344) '#<) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SYSTEM::GCL-TOP-LEVEL. Condition in SYSTEM::GCL-TOP-LEVEL [or a callee]: INTERNAL-SIMPLE-ERROR: The default dispatch macro signalled an error. Broken at SYSTEM::GCL-TOP-LEVEL. Type :H for Help. 1 Return to top level. // Finally, I noticed and removed the unnecessary quote! But the second argument, the // comparator function, is still nonsense, so another error: >>(sort (list 3 6 3 89 65 2344) '#<) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SYSTEM::GCL-TOP-LEVEL. Condition in SYSTEM::GCL-TOP-LEVEL [or a callee]: INTERNAL-SIMPLE-ERROR: The default dispatch macro signalled an error. Broken at SYSTEM::GCL-TOP-LEVEL. 1 (abort) Return to debug level 1. 2 Return to top level. >>>1 Top level. >>2 no such restart. NIL // Finally, the right command! But, I did not quit out of the debug prompt, and so // I am getting the result---finally correct---in truncated form, as the debugger is // trying to minimize the debug mode output. >>(sort (list 3 6 3 89 65 2344) '<) (3 3 6 ...) >>2 no such restart. NIL >>1 Top level. // Finally, I remember to quit out of the debugger _and_ correct all the typos. // Great success! :) >(sort (list 3 6 3 89 65 2344) '<) (3 3 6 65 89 2344) // If I had passed the second argument's function value correctly, it would've worked, too: >(sort (list 3 6 3 89 65 2344) #'<) (3 3 6 65 89 2344) // ...and in reverse order: >(sort (list 3 6 3 89 65 2344) #'>) (2344 89 65 6 3 3) // OK, clearly I was on a roll with errors :) What else could I have done wrong? // Let's see, how about this: >(sort (list 3 6 3 89 65 2344) >) // SORT is a regular function, therefore both of its arguments are evaluated. // So the symbol gets evaluated, too---but it has no symbol binding, only a function binding. // Hence the error: 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 >: Unbound variable: Broken at SORT. Type :H for Help. 1 Return to top level. >>1 Top level. // ... so passing > as a quoted symbol works: >(sort (list 3 6 3 89 65 2344) '>) (2344 89 65 6 3 3) // OK, maybe I should just stick to plain arithmetic :) >(+ 1 2) 3 >(* 2 5) 10 >(+ (* 2 3) 1) 7 >#'+ # // Notice how the CAT1 and CAT2 symbols are quoted. They do not have any values bound to them, // so evaluating them would bring about an error. >(list 'cat1 (list 'cat2)) (CAT1 (CAT2)) // This is the long-form of quoting a symbol. X is not bound. >(quote x) X // So what happens if we evaluate an unbound symbol? This happens, e.g., which we // ask LISP to evaluate it, by typing it into the REPL without the quote: >x 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 X: Unbound variable: Broken at EVAL. Type :H for Help. 1 Return to top level. >>1 Top level. // There's a difference between a symbol not exiting (not yet created by the Read part of the REPL) // and a symbol that's been read (and created) but not bound. // Let's see this for X. Restarting gcl to get rid of my previous reference to X. firefly:~ user$ gcl GCL (GNU Common Lisp) 2.6.12 ANSI Nov 27 2014 05:23:43 Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl) Binary License: GPL due to GPL'ed components: (READLINE UNEXEC) Modifications of this banner must retain notice of a compatible license Dedicated to the memory of W. Schelter Use (help) to get some basic information on how to use GCL. Temporary directory for compiler files set to /private/var/folders/1h/3prjrhy96y55j8jrvttgd_kw0000gp/T/ // So, let's say we reference a symbol X at the prompt. This means we feed it to the Read // part of the REPL, and then to the Eval part. Read works, Eval errors out: >x 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 X: Unbound variable: Broken at EVAL. Type :H for Help. 1 Return to top level. >>1 Top level. // But by this time a symbol X has already been created by the Read part; it's // unbound and "internal", but it exists. >(FIND-SYMBOL "X") X :INTERNAL // OK, restart clean again: firefly:~ user$ gcl GCL (GNU Common Lisp) 2.6.12 ANSI Nov 27 2014 05:23:43 Source License: LGPL(gcl,gmp), GPL(unexec,bfd,xgcl) Binary License: GPL due to GPL'ed components: (READLINE UNEXEC) Modifications of this banner must retain notice of a compatible license Dedicated to the memory of W. Schelter Use (help) to get some basic information on how to use GCL. Temporary directory for compiler files set to /private/var/folders/1h/3prjrhy96y55j8jrvttgd_kw0000gp/T/ // What happens if we ask to look up X by its name? Nothing, it does not exist at all. >(FIND-SYMBOL "X") NIL NIL // So, no symbol named X is there, and it has no representation. Note: in LISP, // a function may return several values; this one returns two NILs. // BTW, what's NIL? It's a symbol, too. It is treated as FALSE by all functions and // special forms that expect a Boolean. It can be also entered as (): >() NIL >nil NIL >NIL NIL // There's a predicate to test for nil. I wish it were called 'nullp', to follow the same // pattern as all predicates, ending in p. >(null 1) NIL >(null ()) T >(null nil) T // Now we feed X for the REPL: >x 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 X: Unbound variable: Broken at EVAL. Type :H for Help. 1 Return to top level. >>1 Top level. // X is unbound (has no value bound to it): >(BOUNDP 'x) NIL // ..but it exists, thanks to the previous attempt to evaluate it---which has the REPL // create it first: >(FIND-SYMBOL "X") X :INTERNAL // OK, let's now try some other predicates. CONSP checks if the (evaluated) argument is a CONS cell: >(CONSP (list 1 2 )) T >(CONSP 1) NIL >(CONSP "foo") NIL // Both 1 and "foo" are the so-called atoms. ATOM is the predicate to test for it. // I wish its name were "atomp", but that's another legacy predicate name without an ending p. >(atom 1) T >(atom "foo") T >(atom (cons 1 nil)) NIL >(atom (list 1 2 3)) NIL // OK, let's set X to something. SETQ is the standard way; it's a special form // that *doesn't* evaluate it first argument, but does evaluate the second. >(setq x 10) 10 >x 10 // SETQ and (set (quote ) ..) are equivalent. >(set (quote x) 10) 10 >(set (quote x) 20) 20 >x 20 // What if we forget the quote or "q"? Then X will be evaluated, and SET // will then attempt to set the value of X's value---which is not a symbol: >(set x 20) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SET. Condition in SET [or a callee]: INTERNAL-SIMPLE-TYPE-ERROR: 20 is not of type SYMBOL: Broken at SET. Type :H for Help. 1 Return to top level. >>1 Top level. // Same deal. Note that X's value is still 20: >(set x (+ 1 2)) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by SET. Condition in SET [or a callee]: INTERNAL-SIMPLE-TYPE-ERROR: 20 is not of type SYMBOL: Broken at SET. Type :H for Help. 1 Return to top level. // But quoting it works. Note that the second argument is, of course, evaluated: >>(set (quote x) (+ 1 2)) 3 >>x 3 >>(set 'x (+ 1 4)) 5 // Oops, I was at the debug prompt all this time, which includes all of LISP / (besides the special debug environment commands). So exiting to the top level. >>1 Top level. >(set 'x (+ 1 4)) 5 >x 5 // Let's put the cats into the right boxes, as per lisp-cons-with-cats.png // First attempt: >(cons 'cat1 'cat2) (CAT1 . CAT2) // No, this is a cons cell with both its CAR and CDR parts taken by symbols. Not what we want; // the cats are unhappy. >(cons 'cat1 'cat2 'cat3) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by CONS. Condition in CONS [or a callee]: INTERNAL-SIMPLE-PROGRAM-ERROR: CONS [or a callee] requires less than three arguments. Broken at CONS. Type :H for Help. 1 Return to top level. >>1 Top level. // OK, cons takes exactly two arguments. Another try: >(cons 'cat1 (cons 'cat2 nil ) ) (CAT1 CAT2) // That's just a single list of length 2, with both cats as elements. We want another box! // What if we through a quote in it? Behold the power of a misplaced quote! >(cons 'cat1 '(cons 'cat2 nil ) ) (CAT1 CONS 'CAT2 NIL) // Now this one is interesting! It's a list with the CONS symbol as a member, and a NIL // as another member, too! Overall, this list has 4 elements, some of which are lists, // too. Draw this expression in cons cells, and then check your answer by deconstructing // it with a sequence of CARs and CDRs. How many cons cells does it have in total? // See my deconstruction in the file 'one-weird-quote.txt'. >(cons 'cat1 (cons (cons 'cat2 nil)) ) Error: Fast links are on: do (si::use-fast-links nil) for debugging Signalled by CONS. Condition in CONS [or a callee]: INTERNAL-SIMPLE-PROGRAM-ERROR: CONS [or a callee] requires more than one argument. Broken at CONS. Type :H for Help. 1 Return to top level. >>1 Top level. // OK, so we need 3 cons cells---and each call to CONS needs two arguments. Got it: >(cons 'cat1 (cons (cons 'cat2 nil) nil ) ) (CAT1 (CAT2)) // Yay! Let's see how the CAR and CDR deconstructors work on this. First, let's give it a symbol of its own: >(setq catbox (cons 'cat1 (cons (cons 'cat2 nil) nil ) )) (CAT1 (CAT2)) >catbox (CAT1 (CAT2)) >(consp catbox) T // Remember, atom and symbolp predicates evaluate its argument! So they get a bunch of cons cells each here: >(atom catbox) NIL >(SYMBOLP catbox) NIL // But of course catbox is a legit symbol: >(SYMBOLP 'catbox) T // ..and bound to a value, too: >(BOUNDP 'catbox) T // In fact, a symbol has several different properties we can examine with respective // functions: >(SYMBOL- SYMBOL-FUNCTION SYMBOL-NAME SYMBOL-PACKAGE SYMBOL-PLIST SYMBOL-VALUE >(SYMBOL-NAME 'catbox) "CATBOX" >(SYMBOL-PACKAGE 'catbox) #<"COMMON-LISP-USER" package> // Let's check the same for some standard functions: >(SYMBOL-PACKAGE 'cons) #<"LISP" package> >(SYMBOL-PACKAGE '+) #<"LISP" package> >(SYMBOL-FUNCTION '+) # '+ // In Common Lisp (but not in Scheme, a later dialect of LISP, which won in academia) // having a value binding and a function binding are different things (think of // it as the underlying implementation's struct for a LISP symbol having two // different slots, both or either or none of which can be set. Typically, standard // functions have a function bound to their functional value slot, but not a symbol value; // that value is looked up when the symbol occurs as a first member of an evaluated list. // Should the same symbol occur as an argument, the Eval of the REPL will attempt to // take its bound value as a symbol, ignoring its function binding. // Compiled functions can be called via their symbol with FUNCALL >(funcall '+ 1 2 3) 6 // Finally, the CAR and CDR: >catbox (CAT1 (CAT2)) >(car catbox) CAT1 // Notice that a CDR of a proper list (not a dotted cons cell like (1 . 2) above) is always a list: >(cdr catbox) ((CAT2)) >(car (cdr catbox)) (CAT2) >(car (car (cdr catbox))) CAT2 // Finally, the cat is out of the box! :) // There are shortcuts for a small number of As and Ds: >(caadr catbox) CAT2