Tag Archives: programming

The less-familiar parts of Lisp for beginners — multiple-value-call

Continuing the series of less commonly-encountered Lisp features, multiple-value-call.  This function is much like funcall, but over multiple values.  If functions returning multiple values is unfamiliar to you, check the brief digression on the topic of values in this earlier post.

When funcall is invoked, if any of the arguments are forms, those forms are evaluated and the primary value is used in the function invocation.  Any additional values are discarded.  The multiple-value-call special operator captures all values returned by those forms and inserts them, in order, in the argument list before calling the function.  This is best illustrated with a simple example:
 

CL-USER> (funcall '+ (values 1 10) (values 1 20))
2
CL-USER> (funcall 'list (values 1 10) (values 1 20))
(1 1)
CL-USER> (multiple-value-call '+ (values 1 10) (values 1 20))
32
CL-USER> (multiple-value-call 'list (values 1 10) (values 1 20))
(1 10 1 20)

The less-familiar parts of Lisp for beginners — muffle-warning

Continuing onward, we arrive at muffle-warning.  This might not seem like a particularly interesting or subtle function, but its behaviour is a bit different from what a newcomer from C++ might expect.

To begin with, you should probably review the articles on exception handling in Lisp.

While we haven’t discussed the warn function yet, we’ll go over it a bit here.  This function generates a Lisp condition (think exception).  Recall that Lisp conditions, if not caught, need not lead to termination.  If a condition is signaled with error, and there is no handler for it, the execution will enter the debugger.  If, instead, signal is used, then an uncaught condition causes execution to continue as if signal had not been invoked.  The warn function is similar to signal, but when it falls through unhandled, or returns from a restart, it prints a diagnostic text on the error stream.  That is, an unhandled warning doesn’t behave as if it had not been invoked at all, but instead produces some diagnostic in an implementation-defined manner.

So, what does muffle-warning do?  It is a function that can be invoked only inside a restart for a warning condition while such a condition is active.  The muffle-warning function suppresses the output from the warning before allowing execution to proceed after the warn invocation.  After the restart exits, execution continues after the warn, but with the normal error stream output suppressed for that one invocation.

The less-familiar parts of Lisp for beginners — method-qualifiers

Now we move to the method-qualifiers function.  This is another example of a function useful in the implementation of Lisp, specifically in the dispatching of methods.  It allows the programmer to distinguish between primary methods, :after methods, :before methods, and :around methods.  While there is likely to be a programmer who has a use for this, I cannot think of a situation where manually dispatching methods is necessary.  The Lisp generic function system, augmented by define-method-combination, seems suitable for any case I can imagine at the moment, so I believe you’re unlikely to find yourself needing to make use of method-qualifiers.

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)