Subject: Re: The LOOP macro
From: rpw3@rpw3.org (Rob Warnock)
Date: Sat, 20 Mar 2004 14:01:16 -0600
Newsgroups: comp.lang.lisp
Message-ID: <sPudnTsfA9GRPsHd3czS-g@speakeasy.net>
Joel Ray Holveck  <joelh@piquan.org> wrote:
+---------------
| Do you have a good example of LOOP's power / flexibility that doesn't
| need much surrounding context to understand?
+---------------

Not off hand. As Peter Seibel noted in a parallel reply, there's no one
specific point that "blows you away", rather, it's the accumulation of
several sub-features that interact well. But oh, what the heck, here are
a few random LOOPs extracted from some real code I'm currently working on:

    ;;; Like UTILS:JOIN-STRINGS, but specialized for quoting elements
    ;;; of SQL VALUES() subclause.
    (defun join-strings/sql-quoted (strings)
      (apply #'concatenate 'string
	     (loop for tail on strings
	       collect "'"
	       collect (sql-escape-single-quotes (car tail))
	       collect "'"
	       when (cdr tail)
		 collect ", ")))

    (defun sql-escape-single-quotes (string)
      (if (position #\' string)             ; Need to do anything at all?
	(let ((escaped (loop for c across string
			 collect c
			 when (eql c #\')
			   collect c)))
	  (coerce escaped 'string))  
	string))                   

Usage:

    > (let ((x '("Here" "is" "Bob's" "house" "and" "Charles'")))
	   (join-strings/sql-quoted x))

    "'Here', 'is', 'Bob''s', 'house', 'and', 'Charles'''"
    > 

Finally, here's one of the more complicated ones from an SQL-related
web form [just fragments]:

    (let* (...lots of setup stuff, then...
	   (adjusted-selections (join-strings selections ", "))
           (predicates 
             (loop for (key . value) in adjusted-bindings
                   and firstp = t then nil
               unless firstp 
                 collect " AND " end
               collect key
               if (equal value "[null]")
                 collect " IS NULL"
               else
                 collect (if match-ci " ILIKE " " LIKE ")
                 and collect (if match-partial "'%" "'")
                 and collect value
                 and collect (if match-partial "%'" "'")
               end))
           (sql-query (apply #'concatenate 'string
                             "SELECT "
                             (when editing? "seq, vseq, ")
                             adjusted-selections
                             " FROM contact_log WHERE vact AND "
                             predicates)))
      (if predicates
        (multiple-value-bind (query-results error)
            (do-person-query sql-query)
          ...use result...)
        (no-search-terms-error-page self s)))


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607