diff options
Diffstat (limited to 'js/games/nluqo.github.io/~bh/ssch27/appendix-cl.html')
-rw-r--r-- | js/games/nluqo.github.io/~bh/ssch27/appendix-cl.html | 523 |
1 files changed, 523 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/ssch27/appendix-cl.html b/js/games/nluqo.github.io/~bh/ssch27/appendix-cl.html new file mode 100644 index 0000000..f4dc775 --- /dev/null +++ b/js/games/nluqo.github.io/~bh/ssch27/appendix-cl.html @@ -0,0 +1,523 @@ +<P> + +<P> +<HTML> +<HEAD> +<TITLE>Simply Scheme Appendix B: Common Lisp</TITLE> +</HEAD> +<BODY> +<CITE>Simply Scheme</CITE>: +<CITE>Introducing Computer Science</CITE> 2/e Copyright (C) 1999 MIT +<H2>Appendix B</H2> +<H1>Common Lisp</H1> + +<TABLE width="100%"><TR><TD> +<IMG SRC="../simply.jpg" ALT="cover photo"> +<TD><TABLE> +<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian +Harvey</A><BR>University of California, Berkeley</CITE> +<TR><TD align="right"><CITE><A HREF="http://ccrma.stanford.edu/~matt">Matthew +Wright</A><BR>University of California, Santa Barbara</CITE> +<TR><TD align="right"><BR> +<TR><TD align="right"><A HREF="../pdf/ssch27.pdf">Download PDF version</A> +<TR><TD align="right"><A HREF="../ss-toc2.html">Back to Table of Contents</A> +<TR><TD align="right"><A HREF="appendix-running.html"><STRONG>BACK</STRONG></A> +chapter thread <A HREF="appendix-simply.html"><STRONG>NEXT</STRONG></A> +<TR><TD align="right"><A HREF="http://mitpress.mit.edu/0262082810">MIT +Press web page for <CITE>Simply Scheme</CITE></A> +</TABLE></TABLE> + +<HR> + +<P>The two most popular dialects of Lisp are Scheme and Common Lisp. This +appendix, which assumes that you have finished the rest of this book, +describes the most important differences between Scheme and Common Lisp so +that you will be able to use Common Lisp if you need to. Common Lisp is the +most popular language among Artificial Intelligence researchers, so AI +courses often use Common Lisp. + +<P><H2>Why Common Lisp Exists</H2> + +<P>Since the beginning of Lisp, many versions of the language were developed. +Each dialect reflected different ideas about the most important capabilities +to include in the language. This diversity made Lisp an exciting arena for +research, but it also meant that a Lisp program written for one dialect +couldn't be used elsewhere. + +<P>In 1984, a group of Lisp developers decided to define a version of Lisp that +would combine the capabilities of all their favorite dialects, so that in +the future they would all use the same language; thus the name "Common" +Lisp. Common Lisp was not the first attempt at a universal Lisp dialect, +but it was more successful than earlier efforts. In 1985 a revision of the +language was begun under the aegis of ANSI, the American National Standards +Institute. This ANSI sponsorship gave Common Lisp an official status that +has contributed to its growing acceptance. + +<P>Since Common Lisp was designed by combining the capabilities of many earlier +dialects, it's an enormous language with nearly 1000 primitives, including +versions of several programs in this book. There is a primitive <CODE>sort</CODE> +procedure, a procedure like <CODE>number-name</CODE> that spells numbers in +English, and a <CODE>substitute</CODE> procedure identical to the one you wrote in +an exercise, to name a few. + +<P>If you're writing your own programs in Common Lisp, you can ignore all the +extra features and just use the capabilities you already know from Scheme. +If you're trying to read someone else's Common Lisp program, we expect that +you will have to look up many primitive procedures in a reference manual. + +<P><H2>Defining Procedures and Variables</H2> + +<P>One minor difference between Scheme and Common Lisp is in the way procedures +are defined. In Common Lisp, + +<P><PRE>(defun square (x) + (* x x)) +</PRE> + +<P>means the same as Scheme's + +<P><PRE>(define (square x) + (* x x)) +</PRE> + +<P>In Scheme, <CODE>define</CODE> is used both for procedures and for variables whose +values aren't procedures. In Common Lisp, procedures are given names by a +mechanism separate from the general variable mechanism; <CODE>defun</CODE> is only +for procedures. To define a variable, use <CODE>defvar</CODE>: + +<P><PRE>common-lisp> (defvar x 6) +6 + +common-lisp> x +6 +</PRE> + +<P>In Common Lisp, <CODE>defvar</CODE> returns the name of the variable you +define. If a variable has already been defined, <CODE>defvar</CODE> will not +change its value; for that you must use <CODE>setq</CODE>. + +<P><H2>The Naming Convention for Predicates</H2> + +<P>In Common Lisp, names of predicate procedures end in a "<CODE>p</CODE>" (for +"predicate") instead of a question mark. Unfortunately, this convention +isn't followed strictly. For example, Common Lisp's version of the <CODE>null?</CODE> predicate is just "<CODE>null</CODE>," not "<CODE>nullp</CODE>." + +<P><H2>No Words or Sentences</H2> + +<P>We've mentioned that Scheme doesn't really have words and +sentences built in; neither does Common Lisp. So none of the following +procedures have Common Lisp equivalents: <CODE>accumulate</CODE>, <CODE>appearances</CODE>, <CODE>before?</CODE>, <CODE>bf</CODE>, <CODE>bl</CODE>, <CODE>butfirst</CODE>, <CODE>butlast</CODE>, <CODE>count</CODE>, <CODE>empty?</CODE>, <CODE>every</CODE>, <CODE>first</CODE>, <CODE>item</CODE>, +<CODE>keep</CODE>, <CODE>last</CODE>, <CODE>member?</CODE>, <CODE>se</CODE>, <CODE>sentence</CODE>, <CODE>word</CODE>, +and <CODE>word?</CODE>. (Common Lisp does have lists, though, and list-related +procedures such as <CODE>map</CODE>, <CODE>reduce</CODE>, <CODE>append</CODE>, and so on <EM>do</EM> +have equivalents.) + +<P><H2>True and False</H2> + +<P>Common Lisp doesn't have the Boolean values <CODE>#t</CODE> and <CODE>#f</CODE>. +Instead, it has a single false value, <CODE>nil</CODE>, which is also the empty +list. + +<P><PRE>common-lisp> (= 2 3) +NIL + +common-lisp> (cdr '(one-word-list)) +NIL + +common-lisp> '() +NIL +</PRE> + +<P><CODE>Nil</CODE> is a strange beast in Common Lisp. It isn't a variable with the +empty list as its value; it's a special self-evaluating symbol. There is +also <CODE>t</CODE>, a self-evaluating symbol with a true value. + +<P><PRE>common-lisp> 'nil +NIL + +common-lisp> nil +NIL + +common-lisp> t +T +</PRE> + +<P>Like Scheme, Common Lisp treats every non-false (i.e., non-<CODE>nil</CODE>) value +as true. But be careful; in Common Lisp + +<P><PRE>common-lisp> (if (cdr '(one-word-list)) 'yes 'no) +</PRE> + +<P>has the value <CODE>NO</CODE>, because the empty list is <CODE>nil</CODE>. + +<P>In Common Lisp's <CODE>cond</CODE>, there is no equivalent to <CODE>else</CODE>; Common +Lisp programmers instead use <CODE>t</CODE> as the condition for their last clause, +like this: + +<P><PRE>(defun sign (n) + (cond ((> n 0) 'positive) + ((= n 0) 'zero) + (t 'negative))) +</PRE> + +<P><H2>Files</H2> + +<P>Common Lisp's mechanism for dealing with files is trivially different from +Scheme's. What Scheme calls "ports," Common Lisp calls "streams." Also, +there is only one procedure for opening streams; the direction is specified +this way: + +<P><PRE>common-lisp> (defvar out-stream (open "outfile" :direction :output)) +#<OUTPUT STREAM "outfile"> + +common-lisp> (close out-stream) +T + +common-lisp> (defvar in-stream (open "infile" :direction :input)) +#<INPUT STREAM "infile"> + +common-lisp> (close in-stream) +T +</PRE> + +<P>Note that the <CODE>close</CODE> procedure closes both input streams and +output streams. + +<P>To <CODE>read</CODE> from an input stream, you must invoke <CODE>read</CODE> with three +arguments: + +<P><PRE>common-lisp> (read stream nil <EM>anything</EM>) +</PRE> + +<P>The <CODE>nil</CODE> indicates that reaching the end of the file should +not be an error. If <CODE>read</CODE> does reach the end of the file, instead of +returning a special end-of-file object it returns its third argument. +It's possible to choose any value as the indicator for reaching the end +of the file: + +<P><PRE>(let ((next (read stream nil 'xyzzy))) + (if (equalp next 'xyzzy) + 'done + (do-something next))) +</PRE> + +<P>It's important to choose an end-of-file indicator that couldn't +otherwise appear as a value in the file. + +<P><H2>Arrays</H2> + +<P>In Common Lisp, vectors are just a special case of the multidimensional <EM>array</EM> data type that you invented in Exercise <A HREF="../ssch23/vectors.html#arrays">23.15</A>. There are quite a +few differences between Common Lisp arrays and Scheme vectors, none very +difficult, but too numerous to describe here. If you need to use arrays, +read about them in a Common Lisp book. + +<P><H2>Equivalents to Scheme Primitives</H2> + +<P>Other than the word and sentence procedures, here is a table of the +Scheme primitives from the table on page <A HREF="appendix-funlist.html#funlist">funlist</A> that have +different names, slightly different behavior, or do not exist at all +in Common Lisp. Scheme procedures not in this list (other than the +word and sentence ones) can be used identically in Common Lisp. + +<P> +<P><TABLE> +<TR><TH>Scheme<TH>Common Lisp +<TR><TD><CODE>align</CODE> +<TD>Common Lisp's <CODE>format</CODE> primitive has a similar purpose +<TR><TD><CODE>begin</CODE> +<TD><CODE>progn</CODE> +<TR><TD><CODE>boolean?</CODE> +<TD>Doesn't exist; see the section in this appendix about true and +false values. +<TR><TD><CODE>c...r</CODE> +<TD>The same, but <CODE>(c...r nil)</CODE> is <CODE>nil</CODE> instead +of an error. +<TR><TD><CODE>children</CODE> +<TD>You can use our version from Chapter 18. +<TR><TD><CODE>close-...-port</CODE> +<TD><CODE>close</CODE> +<TR><TD><CODE>close-all-ports</CODE> +<TD>Doesn't exist. +<TR><TD><CODE>cond</CODE> +<TD>The same, except for <CODE>else</CODE>; use <CODE>t</CODE> instead. +<TR><TD><CODE>datum</CODE> +<TD>You can use our version from Chapter 18. +<TR><TD><CODE>define</CODE> +<TD>Either <CODE>defun</CODE>, for procedure, or +<CODE>defvar</CODE>, otherwise. +<TR><TD><CODE>display</CODE> +<TD><CODE>princ</CODE> +<TR><TD><CODE>eof-object?</CODE> +<TD>See the section on files. +<TR><TD><CODE>equal?</CODE> +<TD><CODE>equalp</CODE> +<TR><TD><CODE>even?</CODE> +<TD><CODE>evenp</CODE> +<TR><TD><CODE>filter</CODE> +<TD><CODE>remove-if-not</CODE> +<TR><TD><CODE>for-each</CODE> +<TD><CODE>mapc</CODE> +<TR><TD><CODE>integer?</CODE> +<TD><CODE>integerp</CODE> +<TR><TD><CODE>lambda</CODE> +<TD>Discussed later in this appendix. +<TR><TD><CODE>list?</CODE> +<TD><CODE>listp</CODE>, except that <CODE>listp</CODE> also returns true +for improper lists. +<TR><TD><CODE>list-ref</CODE> +<TD><CODE>nth</CODE>, except that the arguments come in reverse order. +<TR><TD><CODE>list->vector</CODE> +<TD>See the section about arrays. +<TR><TD><CODE>make-node</CODE> +<TD>You can use our version from Chapter 18. +<TR><TD><CODE>make-vector</CODE> +<TD>See the section about arrays. +<TR><TD><CODE>map</CODE> +<TD><CODE>mapcar</CODE> +<TR><TD><CODE>newline</CODE> +<TD><CODE>terpri</CODE> +<TR><TD><CODE>null?</CODE> +<TD><CODE>null</CODE> +<TR><TD><CODE>number?</CODE> +<TD><CODE>numberp</CODE> +<TR><TD><CODE>odd?</CODE> +<TD><CODE>oddp</CODE> +<TR><TD><CODE>open-...-file</CODE> +<TD>See the section on files. +<TR><TD><CODE>procedure?</CODE> +<TD><CODE>functionp</CODE> +<TR><TD><CODE>quotient</CODE> +<TD><CODE>truncate</CODE> +<TR><TD><CODE>read</CODE> +<TD>Identical except for end of file. See the section on files. +<TR><TD><CODE>read-line</CODE> +<TD>Doesn't exist. (Common Lisp's <CODE>read-line</CODE> is like our +<CODE>read-string</CODE>.) +<TR><TD><CODE>read-string</CODE> +<TD><CODE>read-line</CODE> +<TR><TD><CODE>reduce</CODE> +<TD>The same, but computes <CODE>(f (f a b) c)</CODE> instead of +<CODE>(f a (f b c))</CODE> +<TR><TD><CODE>remainder</CODE> +<TD><CODE>rem</CODE> +<TR><TD><CODE>repeated</CODE> +<TD>Doesn't exist. +<TR><TD><CODE>show</CODE> +<TD><CODE>Doesn't exist but easy to write.</CODE> +<TR><TD><CODE>show-line</CODE> +<TD><CODE>Doesn't exist.</CODE> +<TR><TD><CODE>vector-</CODE><I>anything</I> +<TD>See the section about arrays. +<TR><TD><CODE>write</CODE> +<TD><CODE>prin1</CODE> +</TABLE><P> + + +<P><H2>A Separate Name Space for Procedures</H2> + +<P>All of the differences noted in this table are fairly minor ones, in the +sense that the translation needed to account for these differences requires +little more than renaming. There is one major conceptual difference between +the two languages, however, in the way they treat names of procedures. +Common Lisp allows a procedure and a variable to have the same name. For +example, the program + +<P><PRE>(defun three-copies (list) + (list list list list)) +</PRE> + +<P>is perfectly legal. + +<P><PRE>common-lisp> (three-copies '(drive my car)) +((DRIVE MY CAR) (DRIVE MY CAR) (DRIVE MY CAR)) +</PRE> + +<P>How can Common Lisp tell that one of the <CODE>list</CODE>s means the primitive +procedure, but the other ones mean the formal parameter? Symbols in the +first position in a list (right after an open parenthesis) are taken +to be names of globally defined procedures. + +<P>In Chapter 7 we introduced the image of a blackboard with all the +global variables written on it, which all the Scheme little people can see. +In Common Lisp, there are <EM>two</EM> blackboards: one for global +variables, just as in Scheme, and another one for procedures. The procedure +blackboard contains the primitive procedures and the procedures you define +with <CODE>defun</CODE>. Names in the first position of an expression are looked +up on the procedure blackboard. + +<P>Therefore, the names of procedures are not variables and cannot be used as +actual argument expressions: + +<P><PRE>common-lisp> (sqrt 144) +12 + +common-lisp> (mapcar sqrt '(9 16 25 36)) +ERROR: The variable SQRT is unbound. +</PRE> + +<P>(Common Lisp's equivalent of <CODE>map</CODE> is named <CODE>mapcar</CODE>.) + +<P>How, then, do you tell Common Lisp that you want to use the procedure named +<CODE>sqrt</CODE> as data? You must use the <CODE>function</CODE> special +form.<A NAME="text1" HREF="appendix-cl.html#ft1">[1]</A> + +<P><PRE>common-lisp> (function sqrt) +#<PROCEDURE> + +common-lisp> (mapcar (function sqrt) '(9 16 25 36)) +(3 4 5 6) +</PRE> + +<P><CODE>Function</CODE>'s job is to look up names on the procedure +blackboard. (<CODE>Function</CODE> actually has a more general definition, as +you'll see in a few paragraphs.) + +<P><H2><CODE><B>Lambda</B></CODE></H2> + +<P>In Common Lisp, as in Scheme, procedures can be named or unnamed. Just as +procedure names in Common Lisp are meaningful only in certain contexts, so +are <CODE>lambda</CODE> expressions. They make sense at the beginning of an +expression: + +<P><PRE>common-lisp> ((lambda (x) (* x x)) 4) +16 +</PRE> + +<P>or as the argument to <CODE>function</CODE>: + +<P><PRE>common-lisp> (function (lambda (x) (* x x))) +#<PROCEDURE> + +common-lisp> (mapcar (function (lambda (x) (* x x))) '(3 4 5 6)) +(9 16 25 36) +</PRE> + +<P>but they're meaningless on their own: + +<P><PRE>common-lisp> (lambda (x) (* x x)) +ERROR: LAMBDA is not a function + +common-lisp> (mapcar (lambda (x) (* x x)) '(3 4 5 6)) +ERROR: LAMBDA is not a function +</PRE> + +<P><H2>More about <CODE><B>Function</B></CODE></H2> + +<P>The official rule is that <CODE>function</CODE> returns the "functional +interpretation" of its argument. If the argument is a symbol, that means +looking up the procedure associated with that name. If the argument is a +<CODE>lambda</CODE> expression, it means creating a new procedure. <CODE>Function</CODE> +uses the same rule that's used to interpret the first element of a procedure +invocation. + +<P>Since <CODE>function</CODE> is a very commonly used special form, it has an +abbreviation: + +<P><PRE>common-lisp> (mapcar #'(lambda (x) (* x x)) '(3 4 5 6)) +(9 16 25 36) + +common-lisp> (mapcar #'cdr '((hey jude) (eleanor rigby) (yes it is))) +((JUDE) (RIGBY) (IT IS)) +</PRE> + +<P>Don't confuse + +<P><PRE>#'(lambda (x) (* x x)) +</PRE> + +<P>with + +<P><PRE>'#(lambda (x) (* x x)) +</PRE> + +<P>The first of these is a function that squares its argument; the +second is an array containing three elements. + +<P>It's unfortunate that the abbreviation for <CODE>function</CODE> contains a single +quote mark, because the job of <CODE>function</CODE> is nothing like the job of +<CODE>quote</CODE>. You'll just have to get used to the "hashquote" notation. + +<P><H2>Writing Higher-Order Procedures</H2> + +<P>Think about this attempted translation of the <CODE>map</CODE> procedure: + +<P><PRE>(defun map (fn lst) ;; wrong! + (if (null lst) + '() + (cons (fn (car lst)) + (map fn (cdr lst))))) +</PRE> + +<P>(In Common Lisp, <CODE>null</CODE> is one of the predicates whose names +don't end in "p." Otherwise, this is the same program we showed you in +Chapter 19, except for the <CODE>defun</CODE>, of course.) + +<P>According to our rule about names in the front of a list, this procedure +doesn't work. Think about what happens when we say + +<P><PRE>(map #'square '(1 2 3 4 5)) +</PRE> + +<P>According to the substitution model, the parameters <CODE>fn</CODE> and +<CODE>lst</CODE> are replaced in the body with <CODE>#'square</CODE> and <CODE>'(1 2 3 4 5)</CODE>. But Common Lisp makes an exception for the first +element of a compound expression. It uses the procedure blackboard instead +of substitution: + +<P><PRE>(if (null '(1 2 3 4 5)) + '() + (cons (fn (car '(1 2 3 4 5)) + (map #'square (cdr '(1 2 3 4 5)))))) +</PRE> + +<P>Note that one of the appearances of <CODE>fn</CODE> was left unchanged. +Since there is no global procedure named <CODE>fn</CODE>, this program will produce +an error: + +<P><PRE>common-lisp> (map #'square '(1 2 3 4 5)) +ERROR: FN is not a procedure. +</PRE> + +<P>How, then, do you write higher-order procedures in Common Lisp? The answer is +that you must use <CODE>funcall</CODE>: + +<P><PRE>(defun map (fn lst) + (if (null lst) + '() + (cons (funcall fn (car lst)) + (map fn (cdr lst))))) +</PRE> + +<P><CODE>Funcall</CODE> takes one or more arguments. The first is a +procedure and the rest are arguments for that procedure. It applies that +procedure to the given arguments.<A NAME="text2" HREF="appendix-cl.html#ft2">[2]</A> Since <CODE>fn</CODE> is no longer +at the beginning of a compound expression, the corresponding argument, +<CODE>#'square</CODE>, is substituted for it. + +<P> +<HR> +<A NAME="ft1" HREF="appendix-cl.html#text1">[1]</A> Common Lisp uses the word "function" to mean "procedure," +whether or not the procedure implements a function.<P> +<A NAME="ft2" HREF="appendix-cl.html#text2">[2]</A> This is a lot like <CODE>apply</CODE>, +you may have noticed. Look at the difference: + +<P><PRE>common-lisp> (funcall #'+ 1 2 3) +6 + +common-lisp> (apply #'+ '(1 2 3)) +6 +</PRE> + +<P>In the first case, each argument to <CODE>+</CODE> is a separate argument to <CODE>funcall</CODE>. In the second case, a list of the arguments to <CODE>+</CODE> is a +single argument to <CODE>apply</CODE>. <CODE>Apply</CODE> always takes exactly two +arguments, the procedure and the argument list.<P> +<P><A HREF="../ss-toc2.html">(back to Table of Contents)</A><P> +<A HREF="appendix-running.html"><STRONG>BACK</STRONG></A> +chapter thread <A HREF="appendix-simply.html"><STRONG>NEXT</STRONG></A> + +<P> +<ADDRESS> +<A HREF="../index.html">Brian Harvey</A>, +<CODE>bh@cs.berkeley.edu</CODE> +</ADDRESS> +</BODY> +</HTML> |