Tag Archives: obscure commands

The less-familiar parts of Lisp for beginners — shadow

Next on our list is the shadow function.  This function affects symbols in packages, so if those concepts are unclear to you you might want to read this earlier article.  This function interns a new symbol with the supplied name in the given package if that symbol doesn’t already exist in that package directly (i.e. not through inheritance).  If the symbol exists through inheritance alone, the symbol interned by shadow has the effect of shadowing the inherited symbol in the package.

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

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