The Revised Maclisp ManualThe PitmanualPage C-4
Published by HyperMeta Inc.
 
Prev | Index | Next
Common Lisp Conversion
CL Conversion
Trivial Changes
Easy Changes
Hard Changes
Substandard Code
Cosmetic Changes
User-Defined Functions
Non-Portable Code
Donate

Conv: Hard Changes

[Blue Marble]
Climate Change
How hot
is
too hot?

Slashes and Backslashes

Zetalisp used “/” as the syntax-quoting character. Common Lisp uses “\” for that purpose. The following change is suggested and must be done via Tags Multiple Query Replace. Successive uses of Tags Query Replace will involve far more work and will be much more error-prone.

    //  becomes   /
    #/  becomes   #\
    #\  becomes   #\
    /   becomes   \
    \   becomes   \\

Numeric Functions

The Common Lisp functions / and TRUNCATE replace the Zetalisp function / and the Maclisp function QUOTIENT. The Common Lisp function / never does truncating arithmetic, while the Common Lisp function TRUNCATE always does. This may be one of the hardest conversions to make because you must determine on a case-by-case basis whether or not truncated division is called for. In some cases, the operation may be genuinely overloaded and you may have to do runtime dispatching based on the type of arguments.

The rest of the math operations should behave roughly the same in Common Lisp as they did in Zetalisp. It is only / that causes this problem. The suggested approach is to define a function // which offers the subset of the / functionalities that you desire, and then to incrementally convert your code from doing (// x y) to doing either (TRUNCATE x y) or (/ x y), as appropriate.

If translating from Maclisp, however, recall that the functions +, -, *, and / are different than the Zetalisp operations, since in Zetalisp these operations were "generic" while in Maclisp they were fixnum-only, and that there are also flonum-only operations. The following conversions from Maclisp will generally apply:

  (/ x y)    becomes    (THE FIXNUM (VALUES (TRUNCATE (THE FIXNUM x) (THE FIXNUM y))))
  (* x y)    becomes    (THE FIXNUM (* (THE FIXNUM x) (THE FIXNUM y)))
  (+ x y)    becomes    (THE FIXNUM (+ (THE FIXNUM x) (THE FIXNUM y)))
  (- x y)    becomes    (THE FIXNUM (- (THE FIXNUM x) (THE FIXNUM y)))

  (/$ x y)    becomes    (THE FLOAT (/ (THE FLOAT x) (THE FLOAT y)))
  (*$ x y)    becomes    (THE FLOAT (* (THE FLOAT x) (THE FLOAT y)))
  (+$ x y)    becomes    (THE FLOAT (+ (THE FLOAT x) (THE FLOAT y)))
  (-$ x y)    becomes    (THE FLOAT (- (THE FLOAT x) (THE FLOAT y))))

Uses of the Zetalisp function ATAN2 can be rewritten as uses of the Common Lisp ATAN function. Unfortunately, the Zetalisp function ATAN is not the same as the Common Lisp function ATAN. It is therefore necessary to rename all occurrences of Zetalisp ATAN to some other name, such as ARCTAN. Then convert uses of ATAN2 to ATAN.

  (ATAN y x)   becomes  (ARCTAN y x)
  (ATAN2 y)    becomes  (ATAN y)
  (ATAN2 y x)  becomes  (ATAN y x)

where the following definition for ARCTAN may suffice:

  (DEFUN ARCTAN (X Y) ;This simulates ZL:ATAN
    (LET ((R (ATAN X Y)))
      (COND ((MINUSP R)
             (+ R #.(FLOAT (* 2 PI) 1.0e0)))
            (T R))))

The Maclisp nnn_mmm syntax for numbers is not available. Many uses of this syntax occur in programs which would be non-portable for other reasons, but those which are portable can be rewritten using LSH.

    nnn_mmm    becomes    #.(LSH nnn mmm)

However, since LSH is not a Common Lisp function, you'll have to simulate that. In some cases, the Common Lisp function ASH may help.

Characters

The character input syntax, which for CL is #\char (and for Maclisp and Zetalisp was #/char), causes READ to return character objects (where formerly, in Maclisp/Zetalisp, the characters returned were really just fixnums). Since characters are not fixnums in Common Lisp, the standard arithmetic operations are not defined on them. In particular, characters must be compared using CHAR=, CHAR<, etc. rather than =, <, etc. If the characters being compared are not simply letters or digits, the comparison operators may not be sufficiently well-defined for some applications (except for CHAR=, which is well-defined for all characters).

    (=  zl-char1 zl-char1)  becomes  (CHAR=  cl-char1 cl-char2)
    (>  zl-char1 zl-char2)  becomes  (CHAR>  cl-char1 cl-char2)
    (>= zl-char1 zl-char2)  becomes  (CHAR>= cl-char1 cl-char2)
    (<  zl-char1 zl-char2)  becomes  (CHAR<  cl-char1 cl-char2)
    (>= zl-char1 zl-char2)  becomes  (CHAR<= cl-char1 cl-char2)

Further, it is not possible to add to a character. To add to a character, you must convert it to its numeric code, add to that, then convert back to a character.

    (+ zl-char n)  becomes  (CODE-CHAR (+ (CHAR-CODE cl-char) n))

Input/Output

The functions TYI and TYO have gone away. They are replaced in Common Lisp by the analogous functions READ-CHAR and WRITE-CHAR, respectively. The main difference is that READ-CHAR returns characters (rather than fixnums) and WRITE-CHAR expects characters (rather than fixnums) for a first argument. Because of other changes you will be making in your programs at the same time, it is possible that no change other than the operator name change will be necessary, but it is worth checking things over visually as you are running the Tags Query Replace to make that change. If you are still using antiquated forms such as (TYO fixnum), as in (TYO 65.) instead of (TYO #/A), then you will have some rewriting to do. However, since by the time you do this conversion, you should already have changed #/A to #\A, and since #\A reads as a character instead of a fixnum in Common Lisp, forms like (WRITE-CHAR #\A) will work correctly. Since READ-CHAR returns a character, forms like (WRITE-CHAR (READ-CHAR)) will work as well.

    TYI           becomes  READ-CHAR
    TYO           becomes  WRITE-CHAR
    (TYO fixnum)  becomes  (WRITE-CHAR char) ;where char = (CODE-CHAR fixnum)

The function TYIPEEK can be approximated by PEEK-CHAR. Not all of its arguments are the same, but most useful cases are provided. In particular, a fixnum first argument to TYIPEEK, which was possible in Maclisp but has never been supported in Zetalisp is also not supported in Common Lisp.

    (TYIPEEK)                     becomes  (PEEK-CHAR)
    (TYIPEEK NIL)                 becomes  (PEEK-CHAR NIL)
    (TYIPEEK T)                   becomes  (PEEK-CHAR T)
    (TYIPEEK NIL stream)          becomes  (PEEK-CHAR NIL stream)
    (TYIPEEK T stream)            becomes  (PEEK-CHAR T stream)
    (TYIPEEK NIL stream eof-val)  becomes  (PEEK-CHAR NIL stream NIL eof-val)
    (TYIPEEK T stream eof-val)    becomes  (PEEK-CHAR T stream NIL eof-val)

In Maclisp (and Zetalisp prior to Symbolics Genera Release 7), characters were represented by fixnums. To add CONTROL or META bits to a character, one of +, LOGIOR, or DPB was used. In Common Lisp, the function SET-CHAR-BIT is the appropriate function to use, since characters and fixnums are distinct datatypes. Uses such as (NOT (ZEROP (LOGAND char bits))), (LDB bits ppss char), etc. should be rewritten to use CHAR-BIT.

The Common Lisp functions READ-BYTE and WRITE-BYTE can be used for binary file I/O.

  (SEND binary-stream :TYI)         becomes  (READ-BYTE binary-stream)
  (SEND binary-stream :TYO fixnum)  becomes  (WRITE-BYTE fixnum binary-stream)

The functions EXPLODE, EXPLODEC, EXPLODEN, IMPLODE, and MAKNAM are not directly supported. Here are some sample implementations of functions which roughly implement their functionality:

    (DEFUN EXPLODE (OBJ) 
      (MAP 'LIST #'(LAMBDA (X) (INTERN (STRING X))) (FORMAT NIL "~S" OBJ)))

    (DEFUN EXPLODEC (OBJ)
      (MAP 'LIST #'(LAMBDA (X) (INTERN (STRING X))) (FORMAT NIL "~A" OBJ)))

    (DEFUN EXPLODEN (OBJ)
      (MAP 'LIST #'STRING (FORMAT NIL "~A" OBJ)))

    (DEFUN IMPLODE (CH-LIST)
      (INTERN (MAKNAM CH-LIST)))

    (DEFUN MAKNAM (CH-LIST)
      (MAKE-SYMBOL (FORMAT NIL "~{~C~}" CH-LIST)))

Note that in the above examples, EXPLODEN is not rewritten to return integers as it did in Maclisp. This is because you will probably be rewriting other character operations such as TYI as READ-CHAR, which also returns characters rather than fixnums. Note, too, that these definitions of EXPLODEC and EXPLODEN sometimes do unnecessary string consing. You may wish to replace the

  (FORMAT NIL "~S" OBJ)

with something which does:

  (COND ((STRINGP S) S)
        ((SYMBOLP S) (SYMBOL-NAME S))
        (T (FORMAT NIL "~A" S)))

in order to avoid this extra consing.

The function READLIST can be approximately defined by:

  (DEFUN READLIST (X)
    (READ-FROM-STRING (APPLY #'STRING-APPEND (MAPCAR #'STRING X))))

The functions ASCII and GETCHARN are also not provided by Common Lisp. The best thing is to rewrite these as calls to appropriate Common Lisp string manipulation primitives. For more immediate compatibility, however, these functions may be approximated by the following, which differ from Zetalisp and Maclisp in that they return character objects rather than fixnums:

  (DEFUN ASCII (N)
    (COND ((NUMBERP N) (ASCII (CODE-CHAR N)))
          (T (INTERN (STRING N)))))

  (DEFUN GETCHARN (X N)
    (LET ((IDX (- N 1))
          (STR (STRING X)))
      (UNLESS (OR (>= IDX (STRING-LENGTH STR))
                  (< IDX 0))
        (AREF STR IDX))))

The function FLATC is not provided but can be simulated by one of the following techniques:

     (FLATC string)    becomes    (STRING-LENGTH string)
     (FLATC symbol)    becomes    (STRING-LENGTH (SYMBOL-NAME symbol))
     (FLATC object)    becomes    (STRING-LENGTH (FORMAT NIL "~A" object))

List Manipulation

The three argument case of Zetalisp's EVERY and SOME have been flushed in Common Lisp. The two argument case of Zetalisp's EVERY and SOME now have the arguments in the opposite order. e.g.,

    (EVERY list function) becomes (EVERY function list)
    (SOME  list function) becomes (SOME  function list)

The one argument case of Zetalisp's TYPEP has been flushed in favor of a separate TYPE-OF function in Common Lisp. The two-argument case of TYPEP persists but the names of the types have changed. For details on type names, see Chapter 4 (p42) of CLtL.

    (TYPEP x)         becomes (TYPE-OF x)
    (TYPEP x :FIXNUM) becomes (TYPEP x 'FIXNUM)
    . . . etc.

The Maclisp function LISTEN has been changed to return a boolean value in Common Lisp. In Maclisp, it returned a number (which was non-zero if there was input waiting). The following kinds of rewrites are in order:

    (NOT (ZEROP (LISTEN ...))) becomes (LISTEN ...)
    (ZEROP (LISTEN ...))       becomes (NOT (LISTEN ...))

The recommended strategy is to use Tags Search to find these occurrences and then carefully hand-edit them.

Common Lisp does not prohibit implementations from having arrays with leaders, but it provides no primitives for explicitly manipulating leaders. The special case of creating an array with a 1-length leader which is to be the fill-pointer can be achieved by using the :FILL-POINTER keyword to MAKE-ARRAY. Rather than accessing the fill-pointer via the ARRAY-LEADER operation, you should use the Common Lisp function FILL-POINTER. In the restricted case where ARRAY-HAS-LEADER-P is being used to decide whether ARRAY-LEADER can be used to get the fill-pointer, ARRAY-HAS-FILL-POINTER-P is provided by Common Lisp as a substitute. More complex uses of array leaders have no well-defined meaning in Common Lisp.

    (MAKE-ARRAY ... :LEADER-LIST '(0))  becomes  (MAKE-ARRAY ... :FILL-POINTER 0)
    (ARRAY-LEADER array 0)              becomes  (FILL-POINTER array)
    (ARRAY-HAS-LEADER-P array)          becomes  (ARRAY-HAS-FILL-POINTER-P array)

The variable *NOPOINT has disappeared. In its place is another variable, *PRINT-RADIX*, which is similar but has several important differences. The Zetalisp variable *NOPOINT controlled whether a decimal point was printed after a number when base 10 was in effect. The Common Lisp variable *PRINT-RADIX* controls whether radix information is printed in any base. For example, when radix information is enabled, base 8 numbers are displayed preceded by the character sequence “#o”. For most applications, however, these variables may be treated as if they control the same quantity. The unfortunate problem is that they have inverse meanings (i.e., radix information is printed if *NOPOINT is NIL but if *PRINT-RADIX* is T). Simply doing a Tags Query Replace will not work, since assignments must have values negated. That is,

    *NOPOINT                   becomes (NOT *PRINT-RADIX*)
    (LET ((*NOPOINT T)) ...)   becomes (LET ((*PRINT-RADIX* NIL)) ...)
    (LET ((*NOPOINT NIL)) ...) becomes (LET ((*PRINT-RADIX* T)) ...)
    (LET ((*NOPOINT ...)) ...) becomes (LET ((*PRINT-RADIX* (NOT ...))) ...)
    (SETQ *NOPOINT ...)        becomes (SETQ *PRINT-RADIX* (NOT ...))
    . . . etc.

For this reason, use of Tags Search to find these occurrences and then careful hand-editing is recommended to convert uses of *NOPOINT.

Important Note: In Zetalisp, since *NOPOINT and *PRINT-RADIX* do not share a value cell, the printer must have a way of resolving the situation where *NOPOINT and *PRINT-RADIX* contain either both T or both NIL. By Zetalisp convention, it is an attribute of the current readtable (held by ZL:READTABLE or CL:*READTABLE*, which do share a value cell) that determines which will be used. For example, if the value is a CL readtable, then the value of *PRINT-RADIX* will be looked at. If the value is a ZL readtable, then *NOPOINT will be looked at. It may be useful to bind the value of CL:*READTABLE* to the value of SI:*COMMON-LISP-READTABLE* around the outermost call to your toplevel driver just to assure that the Common Lisp readtable is in effect during I/O operations so that *PRINT-RADIX* can be used uniformly.

[There is an oblique reference here to a facility of the Lisp Machine that allowed symbols to share value cells. This allowed variables that had the same semantics but different names in different packages to be linked to one another. For example, the Zetalisp ZL:BASE variable had its value cell linked to CL:*PRINT-BASE*, so that binding either of those variable would cause both of them to be affected. The problem mentioned in the previous variable was due to the fact that there was no way to link two variables that had opposite sensibilities about how to treat the value. So because ZL:*NOPOINT was a flag to suppress the printing of a radix while CL:*PRINT-RADIX* is a flag to cause printing of a number, it wasn't possible to link these two cells, even though they existed for the same purpose and should only have been changed in lockstep. —KMP, 27 May 2007]

List manipulation functions such as the Maclisp/Zetalisp functions MEMBER, ASSOC, and DELETE, and the Zetalisp function REMOVE work differently in Common Lisp.

For one thing, the three argument case of REMOVE and DELETE is not supported (in the same way, at least). Arguments after the first two are given keyword-style.

They use a predicate EQL (which is fairly similar to EQ, but enough different that you should read up on it if you don't know about it already) rather than EQUAL. This means that, in Common Lisp:

    (SETQ X (LIST (LIST 'A 'B) (LIST 'C 'D)))
     → ((A B) (C D))
    (SETQ Y (LIST 'A 'B))
     → (A B)
    (MEMBER Y X)
     → NIL

In Maclisp/Zetalisp, MEMBER would have returned true for the same (MEMBER Y X). To get that old behavior in Common Lisp, you would have to give a :TEST keyword, specifying #'EQUAL as the comparison predicate.

    (MEMBER obj list)    becomes  (MEMBER obj list :TEST #'EQUAL)
    (ASSOC  obj list)    becomes  (ASSOC  obj list :TEST #'EQUAL)
    (REMOVE obj list)    becomes  (REMOVE obj list :TEST #'EQUAL)
    (REMOVE obj list n)  becomes  (REMOVE obj list :TEST #'EQUAL :COUNT n)
    (DELETE obj list)    becomes  (DELETE obj list :TEST #'EQUAL)
    (DELETE obj list n)  becomes  (DELETE obj list :TEST #'EQUAL :COUNT n)

In some cases, the programmer may know that it doesn't matter whether EQUAL or EQL is called. In those cases, the :TEST part may be omitted. Those cases include, specifically, situations where the object is known to be a character, a symbol, or a number.

    (DELETE char list)    does not change
    (DELETE char list n)  becomes  (DELETE char list :COUNT n)
    (DELETE sym  list)    does not change
    (DELETE sym  list n)  becomes  (DELETE sym  list :COUNT n)
    . . . etc.

Also, remember that if the contents (or at least the type of the contents) of the list is known, it may not be necessary to convert. For example,

    (DELETE anything list-of-chars-syms-and/or-numbers)  does not change

An alternate way to handle this incompatibility is to shadow the symbols MEMBER, ASSOC, REMOVE and DELETE. This may be especially useful during the transition. Having shadowed these symbols, it is possible to define:

   (DEFUN DELETE (X Y &OPTIONAL (COUNT NIL COUNT-P))
     (IF COUNT-P
         (LISP:DELETE X Y :TEST #'EQUAL :COUNT COUNT)
         (LISP:DELETE X Y :TEST #'EQUAL)))

    (DEFUN REMOVE (X Y &OPTIONAL (COUNT NIL COUNT-P))
      (IF COUNT-P
          (LISP:REMOVE X Y :TEST #'EQUAL :COUNT COUNT)
          (LISP:REMOVE X Y :TEST #'EQUAL)))

    (DEFUN MEMBER (X Y)
      (LISP:MEMBER X Y :TEST #'EQUAL))

    (DEFUN ASSOC (X Y)
      (LISP:ASSOC X Y :TEST #'EQUAL))

One problem with this strategy, however, is that incremental converson to CL's DELETE, REMOVE, etc. is not convenient. Having decided to go with this strategy, you could incrementally convert occurrences of (DELETE x y n) to (LISP:DELETE x y :TEST #'EQUAL :COUNT n), but having to type “LISP:” all the time is fairly painful. Also, the fact that you have shadowed the name of a standard Common Lisp function is liable to lead to some confusion for yourself or others at some point, so we point this out as an option but do not recommend its use.

An alternative (and perhaps better) way for handling the problem is to rename uses of DELETE, REMOVE, MEMBER, and ASSOC to other names (e.g., ZDELETE, ZREMOVE, ZMEMBER, and ZASSOC) and define them as above (using simply DELETE instead of LISP:DELETE, REMOVE instead of LISP:LISP:REMOVE, etc. since it would not then be necessary to have shadowed DELETE and friends). Having made this translation, you could lazily convert occurrences of (ZDELETE x y n) to (DELETE x y :TEST #'EQUAL :COUNT n), etc.

Remember, too, that the Maclisp/Zetalisp functions MEMQ, DELQ, and ASSQ, and the Zetalisp function REMQ are not present in Common Lisp. One way to deal with this problem is to simply define them. Assuming that the names MEMBER, DELETE, ASSOC, and REMOVE now refer to their Common Lisp meanings, the following code would work:

 (DEFUN MEMQ (OBJECT LIST) (MEMBER OBJECT LIST :TEST #'EQ))
 (DEFUN ASSQ (OBJECT LIST) (ASSOC  OBJECT LIST :TEST #'EQ))

 (DEFUN DELQ (OBJECT LIST &OPTIONAL (COUNT NIL COUNT-P))
   (IF (NOT COUNT-P)
       (DELETE OBJECT LIST :TEST #'EQ)
       (DELETE OBJECT LIST :TEST #'EQ :COUNT COUNT)))

 (DEFUN REMQ (OBJECT LIST &OPTIONAL (COUNT NIL COUNT-P))
   (IF (NOT COUNT-P)
       (REMOVE OBJECT LIST :TEST #'EQ)
       (REMOVE OBJECT LIST :TEST #'EQ :COUNT COUNT)))

Alternatively, you could rewrite the actual occurrences. One reason for doing that is that frequently the :TEST keyword is not needed. For example, if OBJECT is known to be a symbol, then the test EQL might work equally well. In that case, no :TEST keyword would have to be specified. Also, OBJECT is known to be some other kind of atom, it may be that you should have been using EQL all along—see the manual to be sure.

    (MEMQ symbol list)             becomes  (MEMBER symbol list)
    (MEMQ fixnum list)             becomes  (MEMBER symbol list)
    (MEMQ arbitrary-thing list)    becomes  (MEMBER arbitrary-thing list :TEST #'EQ)

    (ASSQ symbol list)             becomes  (ASSOC symbol list)
    (ASSQ fixnum list)             becomes  (ASSOC symbol list)
    (ASSQ arbitrary-thing list)    becomes  (ASSOC arbitrary-thing list :TEST #'EQ)

    (DELQ symbol list)             becomes  (DELETE symbol list)
    (DELQ fixnum list)             becomes  (DELETE fixnum list)
    (DELQ arbitrary-thing list)    becomes  (DELETE arbitrary-thing list :TEST #'EQ)

    (DELQ symbol list n)           becomes  (DELETE symbol list :COUNT n)
    (DELQ fixnum list n)           becomes  (DELETE fixnum list :COUNT n)
    (DELQ arbitrary-thing list n)  becomes  (DELETE arbitrary-thing list :TEST #'EQ :COUNT n)

    (REMQ symbol list)             becomes  (REMOVE symbol list)
    (REMQ fixnum list)             becomes  (REMOVE fixnum list)
    (REMQ arbitrary-thing list)    becomes  (REMOVE arbitrary-thing list :TEST #'EQ)

    (REMQ symbol list n)           becomes  (REMOVE symbol list :COUNT n)
    (REMQ fixnum list n)           becomes  (REMOVE fixnum list :COUNT n)
    (REMQ arbitrary-thing list n)  becomes  (REMOVE arbitrary-thing list :TEST #'EQ :COUNT n)

Instead of GETL, Common Lisp provides GET-PROPERTIES. Its argument conventions are slightly different. The following rewrite should work fairly effectively,

    (GETL sym ind-list)  becomes  (GET-PROPERTIES (SYMBOL-PLIST sym) ind-list)

Arrays

The Zetalisp function ADJUST-ARRAY-SIZE and the Maclisp function *REARRAY do not exist in Common Lisp. The function ADJUST-ARRAY offers similar capabilities. In the cases that involve only one-dimensional arrays, the rewrite is fairly straightforward. For multi-dimensional arrays, it is somewhat more complicated.

Uses of the Zetalisp function ARRAY-DIMENSION-N and some uses of the Maclisp function ARRAYDIMS should be rewritten using the function ARRAY-DIMENSION:

  (ARRAY-DIMENSION-N array n)  becomes  (ARRAY-DIMENSION array (- n 1))
  (CADR (ARRAYDIMS array))     becomes  (ARRAY-DIMENSION array 0)
  (CADDR (ARRAYDIMS array))    becomes  (ARRAY-DIMENSION array 1)
  ...

Uses of the Zetalisp function ARRAY-LENGTH should be rewritten using the function ARRAY-TOTAL-SIZE:

  (ARRAY-LENGTH array)  becomes  (ARRAY-TOTAL-SIZE array)

Uses of the Zetalisp functions ARRAY-TYPE and the Maclisp function ARRAYDIMS should be rewritten to use ARRAY-ELEMENT-TYPE. However, because the return value of ARRAY-ELEMENT-TYPE is the type of the element and not the type of the array, this rewrite may not be simple. Read the definitions of the relevant functions carefully before deciding on the rewrite that is appropriate.

The functions ARRAY and *ARRAY are not in Common Lisp. The version of them which has a non-NIL first argument must be rewritten very carefully. There is no general strategy for fixing this problem. The case of a NIL first argument is fairly straightforward to update:

    (*ARRAY NIL T dim1 dim2 ...)        becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT NIL)

    (*ARRAY NIL NIL dim1 dim2 ...)      becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT NIL)

    (*ARRAY NIL 'FIXNUM dim1 dim2 ...)  becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT 0   :ELEMENT-TYPE 'FIXNUM)

    (*ARRAY NIL 'FLONUM dim1 dim2 ...)  becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT 0.0 :ELEMENT-TYPE 'FLOAT)

The rewrite for ARRAY is similar, except that ARRAY does not evaluate its first two arguments:

    (ARRAY NIL T dim1 dim2 ...)      becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT NIL)

    (ARRAY NIL NIL dim1 dim2 ...)    becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT NIL)

    (ARRAY NIL FIXNUM dim1 dim2 ...) becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT 0   :ELEMENT-TYPE 'FIXNUM)

    (ARRAY NIL FLONUM dim1 dim2 ...) becomes  (MAKE-ARRAY (LIST dim1 dim2 ...) :INITIAL-ELEMENT 0.0 :ELEMENT-TYPE 'FLOAT)

Structures

The default for DEFSTRUCT in Zetalisp was:

  (DEFSTRUCT (name ... (:CONC-NAME NIL) (:COPIER NIL) ...) ...)

but in Common Lisp Zetalisp defaults to:

 (DEFSTRUCT (name ... :CONC-NAME :COPIER ...) ...)

Also, the MAKE- functions generated by Zetalisp's DEFSTRUCT wanted slot names to be the actual names (and packages) of the slot. In Common Lisp, MAKE- functions want the slot names to be on the keyword package:

  (MAKE-anything slot1 val1 slot2 val2 ...)    becomes    (MAKE-anything :slot1 val1 :slot2 val2 ...)

Symbols and Packages

The MAPATOMS function is not available in Common Lisp. The following definition may suffice for some applications:

    (DEFUN MAPATOMS (FN &OPTIONAL PKG (SEARCH-SUPERIORS-P T))
      (SETQ PKG (COND ((NOT PKG) *PACKAGE*)
                      ((STRINGP PKG) (FIND-PACKAGE PKG))
                      ((SYMBOLP PKG) (FIND-PACKAGE (STRING PKG)))
                      (T PKG)))
      (DO-SYMBOLS (SYM PKG)
        (WHEN (OR SEARCH-SUPERIORS-P (EQL PKG (SYMBOL-PACKAGE SYM)))
          (FUNCALL FN SYM))))

However, the following kind of rewrite may prove simpler:

    (MAPATOMS #'(LAMBDA (var) form1 form2 ...) package)  becomes  (DO-SYMBOLS (var (FIND-PACKAGE package)) form1 form2 ...)

Declarations

The Zetalisp operator LOCAL-DECLARE does not exist in Common Lisp. The following rewrite will work fine in most cases:

  (LOCAL-DECLARE decls . body)    becomes    (LET NIL (DECLARE . decls) . body)

The rewrite is not valid at toplevel, however, since the body of a LET is not considered a toplevel form. If special forms such as DEFUN or EVAL-WHEN occur in the body, a more complicated rewrite may be necessary.

In general, the Maclisp type FLONUM corresponds to the name FLOAT in Common Lisp. Although Common Lisp has additional floating point types.

The Maclisp type FIXNUM approximately corresponds to the Common Lisp type FIXNUM although the specific range of what is and is not a fixnum is not specified by Common Lisp.

Also, very small fixnums in Maclisp might be EQ, but Common Lisp suggests using EQL to compare anything that might be a fixnum since “interned fixnums” are not part of Common Lisp.

The Maclisp type FLONUM approximately corresponds to the name FLOAT in Common Lisp, although Common Lisp also has subtypes of FLOAT.


CL Conversion (1 2 3 (4) 5 6 7 8)


The Revised Maclisp Manual (Sunday Morning Edition)
Published Sunday, December 16, 2007 06:17am EST, and updated Sunday, July 6, 2008.
Prev | Index | Next