[quiz] [QUIZ 3] reader macro

Larry Clapp larry at theclapp.org
Wed Jul 11 12:38:17 UTC 2007


On Tue, Jul 10, 2007 at 09:31:34PM -0400, Matt Pillsbury wrote:
> On Jul 10, 2007, at 11:03 , Larry Clapp wrote:
> >Send answers to the list, preferably with at least one working test
> >case displayed, e.g. something like
> 
> >  cl-user> #"\w \" \s"
> >  "\\w \" \\s"
> 
> Well, I ended up doing something slightly different.
> 
> (defun |#?-READER| (s c n)
[snip]
> This means that whatever character follows the #? becomes the  
> delimeter, like so:
> 
> CL-USER> #?"foo\"bar"
> "foo\"bar"
> 
> CL-USER> #?%foo"bar%
> "foo\"bar"
[snip]

I like it.  Works for me in Lispworks for Linux.

This one struck me kind of funny, for no good reason:

  CL-USER 8 > #?(foo"bar \w \s \t(
  "foo\"bar \\w \\s \\t"

That is, the use of #\( as a delimiter.  It kind of makes me smile and
cringe at the same time.

... So I fixed it:

(defvar *matched-delimiters*
  '(( #\( . #\) )
    ( #\{ . #\} )
    ( #\[ . #\] )
    ( #\< . #\> )))

(defun |#?-READER| (s c n)
  (declare (ignore c n))
  (let* ((term (read-char s))
         (match (assoc term *matched-delimiters*)))
    (when match
      (setf term (cdr match)))
    (with-output-to-string (string)
      (loop
       :for char := (read-char s)
       :until (char= char term)
       :if (and (char= char #\\)
                (char=
                 (peek-char nil s)
                 term))
       :do
       (write-char (read-char s) string)
       :else :do
       (write-char char string)))))

CL-USER 12 > #?(test)
"test"

CL-USER 13 > #?{foo"bar}
"foo\"bar"

CL-USER 14 > #?{foo\}bar}
"foo}bar"

This would make an amusing (and confusing and silly and misleading,
etc) way to comment out some code: slap a #? in front of the leading
#\(.  (But see below.)

Extra credit 1 for newbies: my first version of *matched-delimiters*
looked like this:

  '(( \( . \) )
    ( {  .  } )
    ( [  .  ] )
    ( <  .  > ))

This did not work; explain why.

Extra credit 2 for newbies (really new programmers as well as new
Lispers): My remark about commenting out code by slapping a #? in
front of the leading #\(, above, wouldn't work either, at least not as
the code stands.  Explain why, or extend the code so that it would.

Discussion: Do you like the idea of the #?(string) or hate it?  How
about #?(strings (with (nested (parentheses)))) ?

You know, given all the strange and silly things you can do with read
macros, I'm surprised that Lisp isn't the king of obfuscated code
contests.  But then again maybe it's just a matter of "what's the
point?" "Lisp is easier than Perl to make unreadable if you diddle the
readtable.  Also, water is wet.  Film at 11."  :)

-- Larry




More information about the Quiz mailing list