Monthly Archives: March 2014

The less-familiar parts of Lisp for beginners — mask-field

Next, we arrive at mask-field.  This accessor returns a number which has the masked-off bits set to zero.  It is also setf-able, meaning that it can be used to emulate the behaviour of deposit-field, but changing the integer in place.  Note that in the setf case, as with deposit-field, the byte specifier acts on the inserted number as well.  I’m going to show the Lisp code and the equivalent C code, for clarity:
 

CL-USER> (let* ((orig #xffffffff)
                (mask-width 10)
                (mask-shift 5)
                (mask (byte mask-width mask-shift)))
           (format t "Masked off part is:  #x~X~%"
                   (mask-field mask orig))
           (format t "orig is unchanged:   #x~X~%"
                   orig)
           (format t "deposit-field #x100: #x~X~%"
                   (deposit-field #x100 mask orig))
           (format t "Setting the masked part to #x100...~%")
           (setf (mask-field mask orig) #x100)
           (format t "orig is now:         #x~X~%" 
                   orig))
Masked off part is:  #x7FE0
orig is unchanged:   #xFFFFFFFF
deposit-field #x100: #xFFFF811F
Setting the masked part to #x100...
orig is now:         #xFFFF811F
NIL

And the C:
 
#include <stdio.h>
#include <stdint.h>

int main(void)
{

    uint32_t orig = 0xffffffff;
    uint32_t mask = 0x7fe0;
    uint32_t inserting = 0x100;

    printf("Masked off part is:   0x%x\n", orig & mask);
    printf("orig is unchanged:    0x%x\n", orig);

    printf("Setting the masked part to 0x100...\n");
    orig = ( orig & ~mask ) | (inserting & mask);
    printf("orig is now           0x%x\n", orig);
    return 0;
}

producing output:
 
$ ./mask-field 
Masked off part is:   0x7fe0
orig is unchanged:    0xffffffff
Setting the masked part to 0x100...
orig is now           0xffff811f

The less-familiar parts of Lisp for beginners — map

Our next less-well-known Lisp function is map.  This function works like the more-familiar mapcar, but rather than necessarily returning a list, returns a sequence of the type chosen in the invocation.

Adapting the example in the CLHS:
 

CL-USER> (map 'string
              #'(lambda (x y)
                  (char "01234567890ABCDEF"
                        (mod (+ x y) 16)))
       '(1 2 3 4)
       '(7 8 9 10))
"80BD"
CL-USER> (map 'vector
              #'(lambda (x y)
                  (char "01234567890ABCDEF"
                        (mod (+ x y) 16)))
       '(1 2 3 4)
       '(7 8 9 10))
#(#\8 #\0 #\B #\D)
CL-USER> (map 'list
              #'(lambda (x y)
                  (char "01234567890ABCDEF"
                        (mod (+ x y) 16)))
       '(1 2 3 4)
       '(7 8 9 10))
(#\8 #\0 #\B #\D)
CL-USER> (mapcar
              #'(lambda (x y)
                  (char "01234567890ABCDEF"
                        (mod (+ x y) 16)))
       '(1 2 3 4)
       '(7 8 9 10))
(#\8 #\0 #\B #\D)

The less-familiar parts of Lisp for beginners — make-symbol

Next, we come to the make-symbol function.  The interested reader might want to review the earlier articles about packages and symbols, and about gensym.  So, make-symbol builds a new symbol object, but does not intern it.  Depending on the needs of the programmer, the symbol can be interned, or it can be used uninterned.  Even uninterned symbols are useful, they can be used as local variables in macro expansions, as those that are returned by gensym, and they will never be eq to any other symbol, even another interned or uninterned symbol with the same name:
 

CL-USER> (let ((sym-1 (make-symbol "ABC"))
               (sym-2 (make-symbol "ABC"))
               (sym-3 (intern "ABC")))
           (format t "(eq sym-1 sym-2): ~A~%" (eq sym-1 sym-2))
           (format t "(eq sym-1 sym-3): ~A~%" (eq sym-1 sym-3))
           (format t "(eq sym-2 sym-3): ~A~%" (eq sym-2 sym-3)))
(eq sym-1 sym-2): NIL
(eq sym-1 sym-3): NIL
(eq sym-2 sym-3): NIL
NIL

The less-familiar parts of Lisp for beginners — make-package

Continuing with Lisp features the newcomer to the language might not have encountered is make-package.  This is a function that is rarely called for, other than in its use in the implementation of the defpackage macro.  You should use defpackage whenever that is appropriate.  The make-package function is useful in defining new packages programmatically at run time, as opposed to the more common case of declaring and defining packages in the source code.