--------LET OVER LAMBDA PRESS RELEASE 2--------- Announcing the release of chapter 4, "Read Macros": http://letoverlambda.com/index.cl/guest/chap4.html 1) Post-publication additions to chapter 4 2) Smiley Balancing 2) A "Considered Harmful" 3) Why I don't put asterisks on special variables Post-publication additions to chapter 4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since Let Over Lambda was published, chapter 4 has changed more than any other chapter. There are several known errata that you might like to consider while reading it: http://letoverlambda.com/index.cl/errata As described in chapter 4, we can use read macros to make Edi Weitz's excellent CL-PPCRE library even more convenient: * (#~m/\w+/ "abcd") 0 4 #() #() This works because #~ reads in as a lambda form: * '#~m/\w+/ (LAMBDA (#:STR2) (CL-PPCRE:SCAN "\\w+" #:STR2)) Let Over Lambda's production code now accepts perl-style regular expression modifiers. For instance, here is a case-insensitive regular expression matcher: * '#~m/abc/i (LAMBDA (#:STR2) (CL-PPCRE:SCAN "(?i)abc" #:STR2)) Notice how an embedded modifier is used. This is so that the #~ read macro will create constant string regular expressions. When using #~, regular expressions are guaranteed to be pre-compiled with CL-PPCRE's compiler macro. The final additions to chapter 4's regular expression API are the macros if-match and when-match. These macros automate the common task of using #'subseq to extract and bind CL-PPCRE matches. Just like perl, these macros use the symbols $1, $2, etc: * (if-match (#~m/hello (\w+)/ "hello world") (format t "First match: ~a~%" $1) (format t "Didn't match")) First match: world NIL Unlike perl where $1, $2, etc are global variables, we bind these matches in the lexical scope of the if-match/when-match forms. To be perfectly honest, they are bound in the sub-lexical scope of these forms. For instance, the following form will throw an error because $2 is "unbound" in the nested if-match. * (if-match (#~m/(\w+) (\w+)/ "hello world") (if-match (#~m/he(ll)o/ $1) $2)) Error in function "Top-Level Form": ifmatch: too few matches But you don't need to think about this to use the API. If this doesn't make sense, don't worry. It will all become clear once you read Section 6.6, "Sub-Lexical Scope". Finally, to use this functionality, make sure you load CL-PPCRE *before* you load lol.lisp: http://letoverlambda.com/lol.lisp HCSW: Porting perl to lisp, one step at a time. Smiley Balancing ~~~~~~~~~~~~~~~~ I remember Kent Pitman wrote once that an unbalanced parenthesis can throw off his whole day. Me too. In fact, keeping parens balanced is so important to me that I have adopted a somewhat peculiar pattern to combat unbalanced parens. This is what I call the "happy balancer": (defun match-open-paren (str) (#~m/[(]/ str)) ;) And the "sad balancer": (defun match-close-paren (str) ;( (#~m/[)]/ str)) A "Considered Harmful" ~~~~~~~~~~~~~~~~~~~~~~ I don't consider any programming techniques harmful. This is just an amusing observation I have made since publishing Let Over Lambda. The function that handles the #~ reading is named |#~-reader|. This is a fun use of the fact that lisp symbols can contain any characters you please. I got this idea from CLtL2. However, I have since changed my mind about this naming convention for dispatched read macros. The problem is a latent collision with these names and the #| and |# read macros. Consider what will happen if you comment out code that contains such a symbol: #| ... |#~-reader| ... |# In hindsight, a better naming convention, at least for Let Over Lambda, would perhaps have been |reader-for-#~|. Why I don't put asterisks on special variables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Several people have asked me to clarify why I don't use the *earmuff* convention for special variables, so here goes. First of all, I'm not convinced that unexpected collisions are unconditionally bad. The way I look at it, you always learn something when you encounter a collision and you never learn anything when you don't. My instinct tells me that the earmuff convention is dangerous, or at least that it isn't nearly as open-shut an issue as everyone seems to think. For example, what sort of binding is this? (let (*hello*) ...) It is a lexical binding because I haven't declared *hello* to be special yet. But that's not what you thought when you first looked at it, was it? Or consider this: If you are dogmatic about the earmuffs, why stop there? How about a print-name convention for distinguishing between macros and functions? Instead of with-open-file, we could call it ^with-open-file^ so that we wouldn't need to remember that it is a macro instead of a function. This convention would also reduce collisions like accidentally trying to funcall a macro. Would you use this convention? No, of course you wouldn't. It's stupid. Instead of relying on a semantically meaningless print-name convention, it is a better idea to just name your macros and functions appropriately in the first place. I consider both of these facts features: * Invoking a function looks the same as invoking a macro. * Binding a special variable looks the same as binding a lexical variable (with or without earmuffs). Hope this helps clarify my reasoning, Doug Hoyte Strategic Lead API Designer, HCSW PS. Come to think of it, not even the standard is dogmatic about the earmuffs. There are at least 6 special variables defined by ANSI that don't begin and end with asterisks.