Category Archives: Uncategorized

The less-familiar parts of Lisp for beginners — set-syntax-from-char

The function set-syntax-from-char allows the programmer to copy a read-macro from one character in a particular readtable and duplicate it on possibly a different character in another readtable.  To understand what this means, you may want to review the earlier discussion of readtables.

Here is an example.  It’s not something I would recommend doing in real code, it’s just here for demonstration purposes.  If I want to write some code which contains a lot of strings with embedded double-quote marks, I might be tempted to come up with a new string delimiter to use in that case.  In this code, I copy the meaning of ” into the underscore.  I can then write my code using double-quotes in some places, and underscores in others.  A string that begins with an underscore can only be ended with another underscore, not the double-quote, so this allows me to embed double-quote characters easily in a string.

Naturally, this novel string syntax would break at load time, so we have to use eval-when to modify the readtable before forms using this syntax are read.  Also, note that the colorization is wrong in the code, because SLIME doesn’t know about this new string format, and thinks that I have an unterminated string in my code.  Here’s the code:
set-syntax-from-char.lisp

(eval-when (:compile-toplevel :load-toplevel :execute)
  (set-syntax-from-char #\_ #\"))

(defun demonstrate ()
  (format t "Here is a string: ~S~%" "abcd")
  (format t "Here is another string: ~S~%" _ab"cd_))

Producing the output:
*slime-repl sbcl*
CL-USER> (demonstrate)
Here is a string: "abcd"
Here is another string: "ab\"cd"
NIL

Unreachable server

While I was away on vacation, the server hosting this blog become unresponsive, twice.

The first failure was a kernel oops shortly after mounting my backup disc

kernel BUG at mm/slab.c:3109!

invalid opcode: 0000 [#1] PREEMPT SMP

It was several days before somebody with a key could get to the computer and restart it.  A week later, shortly before I returned from vacation, the machine become unreachable again.  This time, when I came into the house, I could hear a continuous audible alarm from the UPS.  I reset that, and the machine came up and worked normally.

So, two apparently unrelated problems knocking the machine offline when I wasn’t around to handle it.  I checked my SMART logs for the backup disc, there’s no sign that it’s a hardware issue, and the UPS logs are entirely empty of anything incriminating.

If I figure out the causes of either of these failures, I’ll update this post.

Update #1: 2014-06-20

The UPS triggered its alarm again this morning, and the server lost power.  The UPS is an APC Back-UPS ES 750, and a continuous tone indicates that the battery is missing or has failed.  I’ve replaced the battery, and hope that the issue does not repeat.

The less-familiar parts of Lisp for beginners — set-macro-character

The set-macro-character function allows the programmer to modify the readtable.  We’ve talked a bit about modifying the readtable before, in the article on get-dispatch-macro-character.  For a simple example of the use of this function, see the earlier article on eval-when.

There’s not much else to mention here, apart from explaining the difference between a terminating and non-terminating macro character.  One of the optional arguments to set-macro-character allows the programmer to declare that the macro character is non-terminating.  A non-terminating macro character that appears in the middle of a token does not end the token, it only has its special readtable behaviour when it appears at the beginning of a token.  A terminating macro character, conversely, cannot appear as part of a token, because it performs its action when encountered, even inside a symbol name.

The less-familiar parts of Lisp for beginners — search

Next in our walk through less commonly covered Lisp features is search.  This isn’t especially mysterious, but it’s good to point it out, so newcomers know it’s there and don’t start writing their own versions of it.  This function locates a subsequence within a sequence.  Most obviously, the programmer can use it to find a substring in a longer string, but note that, with the :key and :test arguments, more general actions are possible.  There are also options to begin the search from someplace other than the beginning of the sequence, or to find the last occurrence, rather than the first occurrence, of the substring.  Here is an example of things that :key and :test can help with:
search.lisp

(defun demo-case-insensitive-search (haystack needle)
  (search needle haystack :key #'char-downcase :test #'char=))

(defun demo-find-n-letter-word (haystack n)
  (let ((pattern (format nil " ~A " 
                         (make-sequence 'string n 
                                        :initial-element #\A))))
    (search pattern haystack :key #'alpha-char-p)))

(defun demo-find-upper-case-of-word (haystack needle)
  (labels
      ((compare-fcn (char-1 char-2)
         (and (upper-case-p char-2)
              (char= (char-upcase char-1) char-2))))
    (search needle haystack :test #'compare-fcn)))

(defun demonstrate ()
  (let ((stringlist (list "alpha"
                          "beta"
                          "gamma"
                          "delta"
                          "epsilon"
                          "ALPHA"
                          "BETA"
                          "GAMMA"
                          "DELTA"
                          "EPSILON"))
        haystack)
    ;; build haystack, separated with blanks, and with leading
    ;; and trailing blanks
    (setf haystack " ")
    (dolist (word stringlist)
      (setf haystack (concatenate 'string haystack word " ")))
    
    (let ((needle "AlPhA"))
      (format t "case-insensitive search~%")
      (format t "searching for ~S in haystack~%" needle)
      (format t "position= ~A~%" 
              (demo-case-insensitive-search haystack 
                                            needle))
      (format t "~%")
      (format t "upper-case search~%")
      (format t "searching for ~S in haystack~%" needle)
      (format t "position= ~A~%" 
              (demo-find-upper-case-of-word haystack 
                                            needle)))

    (format t "~%")
    (format t "Looking for a 7-letter word~%")
    (format t "position= ~A~%" (demo-find-n-letter-word haystack 7))))
      
        

with output:
*slime-repl sbcl*
CL-USER> (demonstrate)
case-insensitive search
searching for "AlPhA" in haystack
position= 1

upper-case search
searching for "AlPhA" in haystack
position= 32

Looking for a 7-letter word
position= 23
NIL