From: Lowell
Subject: what's the best way to do this?
Date: 
Message-ID: <bmte03$b5$1@mughi.cs.ubc.ca>
I want to print the contents of a list, with colons in between each pair 
of items. I was hoping that there was a simple way I could do this with 
the loop macro. Is there?

Lowell

From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcv4qy58z0m.fsf@famine.OCF.Berkeley.EDU>
Lowell <······@cs.ubc.ca> writes:

> I want to print the contents of a list, with colons in between each pair 
> of items. I was hoping that there was a simple way I could do this with 
> the loop macro. Is there?

Sure:

  (defun show-plist (plist)
    (loop for key in plist by #'cddr
          for val in (rest plist) by #'cddr
          do (format t "~A : ~A~%" key val)))

If PLIST contains an odd number of elements, it will ignore the last
one (because VAL won't see any more list to CDDR down).  You could
also just use FORMAT's iteration facilities:

  (defun show-plist* (plist)
    (format t "~{~A : ~A~%~}" plist))

But in this case, if you have an odd number of elements, you'll get an
error.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Lowell
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <bmter8$pf$1@mughi.cs.ubc.ca>
thanks for the quick response. however, you misunderstood me. What I 
want is for the list (1 2 3) to be printed 1:2:3.

Lowell

Thomas F. Burdick wrote:

> Lowell <······@cs.ubc.ca> writes:
> 
> 
>>I want to print the contents of a list, with colons in between each pair 
>>of items. I was hoping that there was a simple way I could do this with 
>>the loop macro. Is there?
> 
> 
> Sure:
> 
>   (defun show-plist (plist)
>     (loop for key in plist by #'cddr
>           for val in (rest plist) by #'cddr
>           do (format t "~A : ~A~%" key val)))
> 
> If PLIST contains an odd number of elements, it will ignore the last
> one (because VAL won't see any more list to CDDR down).  You could
> also just use FORMAT's iteration facilities:
> 
>   (defun show-plist* (plist)
>     (format t "~{~A : ~A~%~}" plist))
> 
> But in this case, if you have an odd number of elements, you'll get an
> error.
> 
From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcv1xt98yio.fsf@famine.OCF.Berkeley.EDU>
Lowell <······@cs.ubc.ca> writes:

> thanks for the quick response. however, you misunderstood me. What I 
> want is for the list (1 2 3) to be printed 1:2:3.

Ah, that's not the same as working pairwise.

  (defun show-loop (list)
    (loop for (elt . rest) in list
          unless (null rest) do (format t "~A:" elt)))

  (defun show-loop2 (list)
    (loop for elt in (rest list)
          initally (format t "~A" (first list))
          do (format t ":~A" elt)))

  (defun show-format (list)
     (format t "~A~{:~A~}" (first list) (rest list)))

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Lowell
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <bmtfrm$12c$1@mughi.cs.ubc.ca>
thanks for the excellent loop macro mini tutorial :-)

lowell

Thomas F. Burdick wrote:

> Lowell <······@cs.ubc.ca> writes:
> 
> 
>>thanks for the quick response. however, you misunderstood me. What I 
>>want is for the list (1 2 3) to be printed 1:2:3.
> 
> 
> Ah, that's not the same as working pairwise.
> 
>   (defun show-loop (list)
>     (loop for (elt . rest) in list
>           unless (null rest) do (format t "~A:" elt)))
> 
>   (defun show-loop2 (list)
>     (loop for elt in (rest list)
>           initally (format t "~A" (first list))
>           do (format t ":~A" elt)))
> 
>   (defun show-format (list)
>      (format t "~A~{:~A~}" (first list) (rest list)))
> 
From: Lowell
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <bmtg1q$12i$1@mughi.cs.ubc.ca>
oops. I thanked you before testing the functions. The first one doesn't 
work and the second one has some sort of syntax error in it. I don't 
know the loop macro well enough to know what the bugs are.
The last function works well.

Lowell

Thomas F. Burdick wrote:

> Lowell <······@cs.ubc.ca> writes:
> 
> 
>>thanks for the quick response. however, you misunderstood me. What I 
>>want is for the list (1 2 3) to be printed 1:2:3.
> 
> 
> Ah, that's not the same as working pairwise.
> 
>   (defun show-loop (list)
>     (loop for (elt . rest) in list
>           unless (null rest) do (format t "~A:" elt)))
> 
>   (defun show-loop2 (list)
>     (loop for elt in (rest list)
>           initally (format t "~A" (first list))
>           do (format t ":~A" elt)))
> 
>   (defun show-format (list)
>      (format t "~A~{:~A~}" (first list) (rest list)))
> 
From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcvy8vh7ian.fsf@famine.OCF.Berkeley.EDU>
[ Ug, please don't top-quote ]

Lowell <······@cs.ubc.ca> writes:

> oops. I thanked you before testing the functions. The first one doesn't 
> work and the second one has some sort of syntax error in it. I don't 
> know the loop macro well enough to know what the bugs are.
> The last function works well.

Yeah, I think it's time to quit for the night -- my code I was working
on is getting just about as full of typos, too.

> Thomas F. Burdick wrote:
>
> >   (defun show-loop (list)
> >     (loop for (elt . rest) in list
> >           unless (null rest) do (format t "~A:" elt)))

That should be ON, not IN, and I forgot the final case:

  (defun show-loop (list)
    (loop for (elt . rest) on list
          if rest do (format t "~A:" elt)
          else do (format t "~A" elt)))

> >   (defun show-loop2 (list)
> >     (loop for elt in (rest list)
> >           initally (format t "~A" (first list))
> >           do (format t ":~A" elt)))

Er, "initially", not "initally"

  (defun show-loop2 (list)
    (loop for elt in (rest list)
          initially (format t "~A" (first list))
          do (format t ":~A" elt)))

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Jock Cooper
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <m3d6crwxv7.fsf@jcooper02.sagepub.com>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> [ Ug, please don't top-quote ]
> 
> Lowell <······@cs.ubc.ca> writes:
> 
> > oops. I thanked you before testing the functions. The first one doesn't 
> > work and the second one has some sort of syntax error in it. I don't 
> > know the loop macro well enough to know what the bugs are.
> > The last function works well.
> 
> Yeah, I think it's time to quit for the night -- my code I was working
> on is getting just about as full of typos, too.
> 
> > Thomas F. Burdick wrote:
> >
> > >   (defun show-loop (list)
> > >     (loop for (elt . rest) in list
> > >           unless (null rest) do (format t "~A:" elt)))
> 
> That should be ON, not IN, and I forgot the final case:
> 
>   (defun show-loop (list)
>     (loop for (elt . rest) on list
>           if rest do (format t "~A:" elt)
>           else do (format t "~A" elt)))

I am a fan of FORMAT's ~[ operator:

(defun show-loop (list)
     (loop for (elt . rest) on list
           do (format t ····@[:~]" elt rest)))
From: Kenny Tilton
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <_l0lb.14701$pT1.2951@twister.nyc.rr.com>
Jock Cooper wrote:
> ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> 
>>[ Ug, please don't top-quote ]
>>
>>Lowell <······@cs.ubc.ca> writes:
>>
>>
>>>oops. I thanked you before testing the functions. The first one doesn't 
>>>work and the second one has some sort of syntax error in it. I don't 
>>>know the loop macro well enough to know what the bugs are.
>>>The last function works well.
>>
>>Yeah, I think it's time to quit for the night -- my code I was working
>>on is getting just about as full of typos, too.
>>
>>
>>>Thomas F. Burdick wrote:
>>>
>>>
>>>>  (defun show-loop (list)
>>>>    (loop for (elt . rest) in list
>>>>          unless (null rest) do (format t "~A:" elt)))
>>
>>That should be ON, not IN, and I forgot the final case:
>>
>>  (defun show-loop (list)
>>    (loop for (elt . rest) on list
>>          if rest do (format t "~A:" elt)
>>          else do (format t "~A" elt)))
> 
> 
> I am a fan of FORMAT's ~[ operator:
> 
> (defun show-loop (list)
>      (loop for (elt . rest) on list
>            do (format t ····@[:~]" elt rest)))

Looks like a winner, tho in this kind of thread it ain't over till its 
over. You can wear the yellow jersey, anyway.

:)

kenny

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Lennart Staflin
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <m2brsdttbh.fsf@Saturn.lan>
···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
>   (defun show-format (list)
>      (format t "~A~{:~A~}" (first list) (rest list)))

If you want to do it with format, then

   (format t "~{~A~^:~}" list)

is shorter.

//Lennart
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.19.08.05.34.217529@consulting.net.nz>
Hi Thomas F. Burdick,

>> thanks for the quick response. however, you misunderstood me. What I 
>> want is for the list (1 2 3) to be printed 1:2:3.

How about:
(format t "~1{~A~}~{:~A~}" (list (car list)) (cdr list))

I've made sure it prints nothing when the list is nil. I'm sure I could do
better after I learn more format iteration operations.

Regards,
Adam
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.19.08.08.49.620486@consulting.net.nz>
Hi Thomas F. Burdick,

Sorry for the misattribution. I replied to the wrong message.

_Lowell_ wrote:

> thanks for the quick response. however, you misunderstood me. What I 
> want is for the list (1 2 3) to be printed 1:2:3.
 
How about:
(format t "~1{~A~}~{:~A~}" (list (car list)) (cdr list))
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.19.08.13.47.965276@consulting.net.nz>
I originally posted this:
(format t "~1{~A~}~{:~A~}" (list (car list)) (cdr list))

Which simplifies to:
(format t "~1{~A~}~{:~A~}" list (cdr list))

Regards,
Adam
From: Daniel Barlow
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <874qy5s0g2.fsf@noetbook.telent.net>
Adam Warner <······@consulting.net.nz> writes:

> I originally posted this:
> (format t "~1{~A~}~{:~A~}" (list (car list)) (cdr list))
>
> Which simplifies to:
> (format t "~1{~A~}~{:~A~}" list (cdr list))

(format t "~{~A~^:~}" list) ; unless I'm missing something


-dan

-- 

   http://web.metacircles.com/cirCLe_CD - Free Software Lisp/Linux distro
From: Frode Vatvedt Fjeld
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <2h3cdpo824.fsf@vserver.cs.uit.no>
Lowell <······@cs.ubc.ca> writes:

> I want to print the contents of a list, with colons in between each
> pair of items.

It's not using loop, but I think this is the best way in Common Lisp:

  (format t "~{~S~^:~}" list)

This says, in formatish:

  - ~{ loop over a list until we've used up all its elements
      - ~S print (and use up) the next element of the list
      - ~^ if the list is empty, escape the loop
      - :  print a colon
      - ~} re-iterate the loop.

-- 
Frode Vatvedt Fjeld
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.19.11.42.50.16284@consulting.net.nz>
Hi Frode Vatvedt Fjeld,

> Lowell <······@cs.ubc.ca> writes:
> 
>> I want to print the contents of a list, with colons in between each
>> pair of items.
> 
> It's not using loop, but I think this is the best way in Common Lisp:
> 
>   (format t "~{~S~^:~}" list)
> 
> This says, in formatish:
> 
>   - ~{ loop over a list until we've used up all its elements
>       - ~S print (and use up) the next element of the list
>       - ~^ if the list is empty, escape the loop
>       - :  print a colon
>       - ~} re-iterate the loop.

Thanks for posting the ultimate FORMAT solution (the piece I was missing
was the escape construct).

I suspect this is the best LOOP that can be constructed:

(loop for item in list
      for first = t then nil
      if first do (format t "~S" item)
      else do (format t ":~S" item))

Regards,
Adam
From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcvu1656uc1.fsf@famine.OCF.Berkeley.EDU>
> Hi Frode Vatvedt Fjeld,
>
> >       - ~^ if the list is empty, escape the loop

Ah, I forgot about that one!  That does make everything nicer, doesn't it :)

Adam Warner <······@consulting.net.nz> writes:

> I suspect this is the best LOOP that can be constructed:
> 
> (loop for item in list
>       for first = t then nil
>       if first do (format t "~S" item)
>       else do (format t ":~S" item))

That's less efficient than using initially, and the style can be less
clear for more complicated loops.  Knuth has an essay somewhere, where
he rails against structured programming dogmatists for making
constructions like the above, which essentially interpret a tagbody;
better to just use tagbody, but far better to use more flexible
control structure, even if it doesn't quite count as "structured" (in
the style wars of the day).  In this case, LOOP has INITIALLY and
FINALLY, so we should use them.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Kenny Tilton
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <N0xkb.909$pT1.677@twister.nyc.rr.com>
Adam Warner wrote:

> Hi Frode Vatvedt Fjeld,
> 
> 
>>Lowell <······@cs.ubc.ca> writes:
>>
>>
>>>I want to print the contents of a list, with colons in between each
>>>pair of items.
>>
>>It's not using loop, but I think this is the best way in Common Lisp:
>>
>>  (format t "~{~S~^:~}" list)
>>
>>This says, in formatish:
>>
>>  - ~{ loop over a list until we've used up all its elements
>>      - ~S print (and use up) the next element of the list
>>      - ~^ if the list is empty, escape the loop
>>      - :  print a colon
>>      - ~} re-iterate the loop.
> 
> 
> Thanks for posting the ultimate FORMAT solution (the piece I was missing
> was the escape construct).
> 
> I suspect this is the best LOOP that can be constructed:
> 
> (loop for item in list
>       for first = t then nil
>       if first do (format t "~S" item)
>       else do (format t ":~S" item))

Tilton's Law: move conditionals in as far as possible:

  (loop for item in '(1 2 3)
     for first = t then nil
     do (format t "~{~c~}~S" (unless first (list #\:)) item))

Is there a simpler way than the null list trick to print nothing? It 
would look like:

     (format "^[what?]:^s" first item)

kenny

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcvr8196tyd.fsf@famine.OCF.Berkeley.EDU>
Kenny Tilton <·······@nyc.rr.com> writes:

> Tilton's Law: move conditionals in as far as possible:
> 
>   (loop for item in '(1 2 3)
>      for first = t then nil
>      do (format t "~{~c~}~S" (unless first (list #\:)) item))
> 
> Is there a simpler way than the null list trick to print nothing? It 
> would look like:
> 
>      (format "^[what?]:^s" first item)

Use Burdick's Law: when moving conditionals, aim carefully:

  (loop for item in list
        for first = t then nil ; ick
        do (format t (if first "~S" ":~S") item))

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Edi Weitz
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <877k312fzo.fsf@bird.agharta.de>
On 19 Oct 2003 10:03:22 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

> Use Burdick's Law: when moving conditionals, aim carefully:
> 
>   (loop for item in list
>         for first = t then nil ; ick
>         do (format t (if first "~S" ":~S") item))

Dumb question: Wouldn't this probably prevent the compiler from
generating an efficient formatter function at compile time? (I know,
if it were sufficiently smart... But what about existing
implementations?)

Edi.
From: Duane Rettig
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <4znfwyby0.fsf@beta.franz.com>
Edi Weitz <···@agharta.de> writes:

> On 19 Oct 2003 10:03:22 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> 
> > Use Burdick's Law: when moving conditionals, aim carefully:
> > 
> >   (loop for item in list
> >         for first = t then nil ; ick
> >         do (format t (if first "~S" ":~S") item))
> 
> Dumb question: Wouldn't this probably prevent the compiler from
> generating an efficient formatter function at compile time? (I know,
> if it were sufficiently smart... But what about existing
> implementations?)

The only dumb questions are the ones not asked.  You're exactly
right; this is inefficient, because it removes the control strings
from their rightful position (as a _single_ format string with
a conditional control) and they are thus harder to optimize.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcvoewc7aex.fsf@famine.OCF.Berkeley.EDU>
Duane Rettig <·····@franz.com> writes:

> Edi Weitz <···@agharta.de> writes:
> 
> > On 19 Oct 2003 10:03:22 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> > 
> > > Use Burdick's Law: when moving conditionals, aim carefully:
> > > 
> > >   (loop for item in list
> > >         for first = t then nil ; ick
> > >         do (format t (if first "~S" ":~S") item))
> > 
> > Dumb question: Wouldn't this probably prevent the compiler from
> > generating an efficient formatter function at compile time? (I know,
> > if it were sufficiently smart... But what about existing
> > implementations?)
> 
> The only dumb questions are the ones not asked.  You're exactly
> right; this is inefficient, because it removes the control strings
> from their rightful position (as a _single_ format string with
> a conditional control) and they are thus harder to optimize.

Yeah, if we're at all concerned with efficiency, my loop above *still*
didn't aim right with the conditional.  Using our good friend format,
we can get the best of both worlds:

  (defun hov-and-r. (list)
    (loop for item in list
          for format = (formatter "~S") then (formatter ":~S")
          do (format t format item)))

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Pascal Bourguignon
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <87wub0fwqo.fsf@thalassa.informatimago.com>
Duane Rettig <·····@franz.com> writes:

> Edi Weitz <···@agharta.de> writes:
> 
> > On 19 Oct 2003 10:03:22 -0700, ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> > 
> > > Use Burdick's Law: when moving conditionals, aim carefully:
> > > 
> > >   (loop for item in list
> > >         for first = t then nil ; ick
> > >         do (format t (if first "~S" ":~S") item))
> > 
> > Dumb question: Wouldn't this probably prevent the compiler from
> > generating an efficient formatter function at compile time? (I know,
> > if it were sufficiently smart... But what about existing
> > implementations?)
> 
> The only dumb questions are the ones not asked.  You're exactly
> right; this is inefficient, because it removes the control strings
> from their rightful position (as a _single_ format string with
> a conditional control) and they are thus harder to optimize.

On the other hand a peephole optimizer could still optimize it in that
case (unrolling the first iteration).

-- 
__Pascal_Bourguignon__
http://www.informatimago.com/
Do not adjust your mind, there is a fault in reality.
Lying for having sex or lying for making war?  Trust US presidents :-(
From: Duane Rettig
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <44qy4zqo4.fsf@beta.franz.com>
Kenny Tilton <·······@nyc.rr.com> writes:

> Tilton's Law: move conditionals in as far as possible:
> 
>   (loop for item in '(1 2 3)
>      for first = t then nil
>      do (format t "~{~c~}~S" (unless first (list #\:)) item))

Hmm.  Tilton breaks Tilton's Law.

> Is there a simpler way than the null list trick to print nothing? It
> would look like:
> 
> 
>      (format "^[what?]:^s" first item)

Well, other than forgetting the stream designator, I think what
you want is

    (format t "~:[:~;~]~s" first item)

A little busy, but very efficient.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Kenny Tilton
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <usJkb.7576$pT1.4804@twister.nyc.rr.com>
Duane Rettig wrote:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>Tilton's Law: move conditionals in as far as possible:
>>
>>  (loop for item in '(1 2 3)
>>     for first = t then nil
>>     do (format t "~{~c~}~S" (unless first (list #\:)) item))
> 
> Hmm.  Tilton breaks Tilton's Law.

There are so many, which one do you mean? How much further in can it 
get? Mind you, I was a little reductio absurdum there and was really 
hoping for...

>>Is there a simpler way than the null list trick to print nothing? It
>>would look like:
>>
>>
>>     (format "^[what?]:^s" first item)
> 
> 
> Well, other than forgetting the stream designator, I think what
> you want is
> 
>     (format t "~:[:~;~]~s" first item)

Sweet! So at long last we can answer the OP's question, if they have not 
given us up for lost. One of:

(loop for item in '(1 2 3)
     for first = t then nil
     do (format t "~:[:~;~]~S" first item))

...or:

(let ((first t))
   (dolist (item '(1 2 3))
     (format t "~:[:~;~]~S" first item)
     (setf first nil)))

The two fors bug me (screams out nested to me, which it isn't), and the 
"t then nil" thing is a little cutesy, but with a little LOOP 
familiarity both those seem fine, so I'd go with the LOOP version.

Hey, this was supposed to be LOOP weekend, not FORMAT. Speaking of 
which, yeah, the format string complexity might be too much for a 
newbie, but OTOH there is an implicit message here which is good to get 
across early: FORMAT is smarter than your average printf bear.

kenny

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Thomas F. Burdick
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <xcvllrg7a31.fsf@famine.OCF.Berkeley.EDU>
Kenny Tilton <·······@nyc.rr.com> writes:

> Duane Rettig wrote:
>
> >     (format t "~:[:~;~]~s" first item)
> 
> Sweet!

Definately. I kinda knew you could do that, but it was way in the back
of my head with the cobwebs and 6502 opcodes.

> So at long last we can answer the OP's question, if they have not
> given us up for lost. One of:

Ahem.  I believe the OP asked about loop, not format.  I've been happy
for the little format tutorial, but if we're talking about the OP's
question, I think the answer is:

  for item in (rest list)
  initially ...
  do ...
or
  for item in list
  for first = t then nil
or
  for (item . rest) on list

with the last being a double-whammy loop lesson, even if it's not the
best answer.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Lowell
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <bn0d41$gs8$3@mughi.cs.ubc.ca>
Thomas F. Burdick wrote:
> Ahem.  I believe the OP asked about loop, not format.  I've been happy
> for the little format tutorial,

true, but I'm really liking the conciseness of the format expressions 
:-) I didn't realize it was so powerful.

The lessons in loop-ology have been very insightful too.

Lowell
From: Kenny Tilton
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <o1Vkb.12805$pT1.1951@twister.nyc.rr.com>
Thomas F. Burdick wrote:

> Kenny Tilton <·······@nyc.rr.com> writes:
> 
> 
>>Duane Rettig wrote:
>>
>>
>>>    (format t "~:[:~;~]~s" first item)
>>
>>Sweet!
> 
> 
> Definately. I kinda knew you could do that, but it was way in the back
> of my head with the cobwebs and 6502 opcodes.
> 
> 
>>So at long last we can answer the OP's question, if they have not
>>given us up for lost. One of:
> 
> 
> Ahem.  I believe the OP asked about loop, not format. 

Poppycock. (laying off "nonsense" for a while.)

Lowell wrote:
> I want to print the contents of a list, with colons in between each pair 
> of items. I was hoping that there was a simple way I could do this with 
> the loop macro.

(a) Only an extreme literal reading with the mind closed to the first 
sentence leaves one believing the only welcome solutions use loop and 
nothing but loop (since of the ones I offered did use loop).

(ii) Since when do CLLers or hardware store clerks limit themselves to 
the tool requested when trying to help someone get something done?

Tell you what, let's see which solution Lowell goes for and see who is 
right.

:)

kenny


-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Lowell
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <bn0cvb$gs8$2@mughi.cs.ubc.ca>
Huh! And those Perl-ers think their language has more than one way to do 
it! (it seems to be written on every other page of Learning Perl) They 
would surely be impressed with lisp :-)

Lowell

Kenny Tilton wrote:

> 
> Duane Rettig wrote:
> 
>> Kenny Tilton <·······@nyc.rr.com> writes:
>>
>>
>>> Tilton's Law: move conditionals in as far as possible:
>>>
>>>  (loop for item in '(1 2 3)
>>>     for first = t then nil
>>>     do (format t "~{~c~}~S" (unless first (list #\:)) item))
>>
>>
>> Hmm.  Tilton breaks Tilton's Law.
> 
> 
> There are so many, which one do you mean? How much further in can it 
> get? Mind you, I was a little reductio absurdum there and was really 
> hoping for...
> 
>>> Is there a simpler way than the null list trick to print nothing? It
>>> would look like:
>>>
>>>
>>>     (format "^[what?]:^s" first item)
>>
>>
>>
>> Well, other than forgetting the stream designator, I think what
>> you want is
>>
>>     (format t "~:[:~;~]~s" first item)
> 
> 
> Sweet! So at long last we can answer the OP's question, if they have not 
> given us up for lost. One of:
> 
> (loop for item in '(1 2 3)
>     for first = t then nil
>     do (format t "~:[:~;~]~S" first item))
> 
> ...or:
> 
> (let ((first t))
>   (dolist (item '(1 2 3))
>     (format t "~:[:~;~]~S" first item)
>     (setf first nil)))
> 
> The two fors bug me (screams out nested to me, which it isn't), and the 
> "t then nil" thing is a little cutesy, but with a little LOOP 
> familiarity both those seem fine, so I'd go with the LOOP version.
> 
> Hey, this was supposed to be LOOP weekend, not FORMAT. Speaking of 
> which, yeah, the format string complexity might be too much for a 
> newbie, but OTOH there is an implicit message here which is good to get 
> across early: FORMAT is smarter than your average printf bear.
> 
> kenny
> 
From: Kenny Tilton
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <%cVkb.12932$pT1.11871@twister.nyc.rr.com>
Lowell wrote:

> Huh! And those Perl-ers think their language has more than one way to do 
> it! (it seems to be written on every other page of Learning Perl) They 
> would surely be impressed with lisp :-)

Send 'em over. :)

It is kinda funny that your question fell into an intersection of two 
Lisp oddities, LOOP and FORMAT. Each are embedded languages cum Lisp 
commands, neither language being very Lisp-ish. On top of that, one errs 
on the side of bogus natural language-like loquaciousness, while the 
other strays (I am told) towards Perl-ish conciseness-unto-unreadability.

On top of that^2, I have been doing Lisp heavily for eight years and I 
am just learning LOOP and FORMAT now. Fun question.

kenny

-- 
http://tilton-technology.com
What?! You are a newbie and you haven't answered my:
  http://alu.cliki.net/The%20Road%20to%20Lisp%20Survey
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.20.23.07.02.49376@consulting.net.nz>
Hi Kenny Tilton,

> It is kinda funny that your question fell into an intersection of two 
> Lisp oddities, LOOP and FORMAT. Each are embedded languages cum Lisp 
> commands, neither language being very Lisp-ish. On top of that, one errs 
> on the side of bogus natural language-like loquaciousness, while the 
> other strays (I am told) towards Perl-ish conciseness-unto-unreadability.
> 
> On top of that^2, I have been doing Lisp heavily for eight years and I 
> am just learning LOOP and FORMAT now. Fun question.

(defmacro cs (&rest args)
  `(concatenate 'string ,@args))

Here's a recursive version with similar functionality:

(defun colons (list &optional (first t))
  (if list
      (cs (if first
              (format nil "~S" (car list))
              (format nil ":~S" (car list)))
          (colons (cdr list) nil))
      ""))

* (colons nil)

""
* (colons '(1))

"1"
* (colons '(1 2))

"1:2"
* (colons '(1 2 3))

"1:2:3"

Regards,
Adam
From: Frode Vatvedt Fjeld
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <2hoewbkm6x.fsf@vserver.cs.uit.no>
Adam Warner <······@consulting.net.nz> writes:

> (defmacro cs (&rest args)
>   `(concatenate 'string ,@args))

I believe this should be a function, not a macro.

-- 
Frode Vatvedt Fjeld
From: Björn Lindberg
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <hcssmllo60g.fsf@tjatte.nada.kth.se>
Frode Vatvedt Fjeld <······@cs.uit.no> writes:

> Adam Warner <······@consulting.net.nz> writes:
> 
> > (defmacro cs (&rest args)
> >   `(concatenate 'string ,@args))
> 
> I believe this should be a function, not a macro.

Why? He seems to only want cs to be an alias of concatenate 'string,
which to me looks like a good use for a macro. I could be wrong
though.


Bj�rn
From: Frode Vatvedt Fjeld
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <2h8yndjp81.fsf@vserver.cs.uit.no>
·······@nada.kth.se (Bj�rn Lindberg) writes:

> Why? He seems to only want cs to be an alias of concatenate 'string,
> which to me looks like a good use for a macro. I could be wrong
> though.

It's got a functional interface, so use a function. Using macros like
this, more or less as text substitution, is a bad habit one learns as
a C programmer, I think.

-- 
Frode Vatvedt Fjeld
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.22.20.47.32.575996@consulting.net.nz>
Hi Frode Vatvedt Fjeld,

> ·······@nada.kth.se (Bj�rn Lindberg) writes:
> 
>> Why? He seems to only want cs to be an alias of concatenate 'string,
>> which to me looks like a good use for a macro. I could be wrong though.
> 
> It's got a functional interface, so use a function. Using macros like
> this, more or less as text substitution, is a bad habit one learns as a
> C programmer, I think.

First you believe. Now you think. Let me know when you have a valid point.

Regards,
Adam
From: Frode Vatvedt Fjeld
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <2h4qy1j8md.fsf@vserver.cs.uit.no>
Adam Warner <······@consulting.net.nz> writes:

> First you believe. Now you think. Let me know when you have a valid
> point.

Sure, if you promise not to let me know the next time you have nothing
to say.

-- 
Frode Vatvedt Fjeld
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.22.23.06.33.452207@consulting.net.nz>
Hi Frode Vatvedt Fjeld,

>> First you believe. Now you think. Let me know when you have a valid
>> point.
> 
> Sure, if you promise not to let me know the next time you have nothing
> to say.

I do not have to justify every minutia of my coding decisions.

The approach does not have the pitfalls of C-like text substitution. The
approach guarantees that the code will have the same runtime performance.
The approach has no extra function calling overhead nor risk that an
inline optimisation declaration is ignored by an implementation. And in
experience I have found that real code becomes vastly more legible when it
no longer line wraps on screen because 19 characters of horizontal space
(versus 2) are taken up to write down the name of a common operation.

The only possible complaint you could have is that it is not possible to
operate upon #'cs:

* (apply #'cs '("a" "b" "c"))


cs is a macro.
   [Condition of type simple-type-error]

Yet #'concatenate is still available for exactly this approach.

This reply is the macroexpansion of "Let me know when you have a valid
point."

Regards,
Adam
From: Barry Margolin
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <CsElb.177$lK3.91@news.level3.com>
In article <······························@consulting.net.nz>,
Adam Warner  <······@consulting.net.nz> wrote:
>The approach does not have the pitfalls of C-like text substitution. The
>approach guarantees that the code will have the same runtime performance.
>The approach has no extra function calling overhead nor risk that an
>inline optimisation declaration is ignored by an implementation. And in

If you're that concerned about such minute performance details, why would
you be caught dead using a compiler that ignores inline declarations?  It's
likely that such a compiler also lacks other optimizations; so even though
this particular operation will be .01% faster, everything else will be 5%
slower.  The saying "penny wise, pound foolish" comes to mind.

>experience I have found that real code becomes vastly more legible when it
>no longer line wraps on screen because 19 characters of horizontal space
>(versus 2) are taken up to write down the name of a common operation.
>
>The only possible complaint you could have is that it is not possible to
>operate upon #'cs:
>
>* (apply #'cs '("a" "b" "c"))
>
>
>cs is a macro.
>   [Condition of type simple-type-error]
>
>Yet #'concatenate is still available for exactly this approach.

But this is one of the situations where the abbreviation is most useful.
Consider passing it to a mapping function.  Which is easier:

(mapcar #'cs ...)

or

(mapcar (lambda (x y) (cs x y)) ...)

Good Lisp programming style uses macros *only* for things that depend on
the special behavior of macro expansion, i.e. that the parameters are not
automatically evaluated.  Things that act function-like should be defined
as functions.  This is also suggested by the Rule or Least Surprise.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.23.03.44.54.954793@consulting.net.nz>
Hi Barry Margolin,

>>The approach does not have the pitfalls of C-like text substitution. The
>>approach guarantees that the code will have the same runtime
>>performance. The approach has no extra function calling overhead nor
>>risk that an inline optimisation declaration is ignored by an
>>implementation. And in
> 
> If you're that concerned about such minute performance details, why
> would you be caught dead using a compiler that ignores inline
> declarations?  It's likely that such a compiler also lacks other
> optimizations; so even though this particular operation will be .01%
> faster, everything else will be 5% slower.  The saying "penny wise,
> pound foolish" comes to mind.

You appear to have not considered the implementation with vastly differing
performance characteristics: CLISP. If you did so you would not be
making up 1/10,000 faster statistics in order to reinforce your point :-)

Here's a pathological example:

(defmacro cs-macro (&rest args)
  `(concatenate 'string ,@args))

(declaim (inline cs-fn))
(defun cs-fn (&rest args)
  (apply #'concatenate 'string args))

(defconstant +strings+ (loop for i from 1 to 1000000
			     collect (cons #1=(format nil "~S" i) #1#)))

(defun test-cs-fn ()
  (loop for (str1 . str2) in +strings+
	sum (length (cs-fn str1 str2))))

(defun test-cs-macro ()
  (loop for (str1 . str2) in +strings+
	sum (length (cs-macro str1 str2))))


Running CLISP compiled byte code, (test-cs-fn) runs about 33% slower on my
computer (including spending about 40% longer garbage collecting). CMUCL
appears to run both tests at about the same speed (as expected).

Another way to compare this is by looking at the byte code generated by
the two forms (cs-fn "a" "b") and (cs-macro "a" "b"):

(disassemble '(cs-fn "a" "b")) generates 7 byte-code instructions:
0     (const&push 0)                      ; "a"
1     (const&push 1)                      ; "b"
2     (list&push 2)
4     (const&push 2)                      ; #<system-function concatenate>
5     (const&push 3)                      ; string
6     (load 2)
7     (apply&skip&ret 1 2)

(disassemble '(cs-macro "a" "b")) generates 5 byte-code instructions:
0     (const&push 0)                      ; string
1     (const&push 1)                      ; "a"
2     (const&push 2)                      ; "b"
3     (callsr 2 37)                       ; concatenate
6     (skip&ret 1)

>>experience I have found that real code becomes vastly more legible when
>>it no longer line wraps on screen because 19 characters of horizontal
>>space (versus 2) are taken up to write down the name of a common
>>operation.
>>
>>The only possible complaint you could have is that it is not possible to
>>operate upon #'cs:
>>
>>* (apply #'cs '("a" "b" "c"))
>>
>>
>>cs is a macro.
>>   [Condition of type simple-type-error]
>>
>>Yet #'concatenate is still available for exactly this approach.
> 
> But this is one of the situations where the abbreviation is most useful.
> Consider passing it to a mapping function.  Which is easier:
> 
> (mapcar #'cs ...)
> 
> or
> 
> (mapcar (lambda (x y) (cs x y)) ...)
> 
> Good Lisp programming style uses macros *only* for things that depend on
> the special behavior of macro expansion, i.e. that the parameters are
> not automatically evaluated.  Things that act function-like should be
> defined as functions.  This is also suggested by the Rule or Least
> Surprise.

OK you've made some good points (and I suspect Frode Vatvedt Fjeld would
now express them the same way. I'm sorry I fought you over this Frode).

Within reason I am now prepared to ignore harm to CLISP's performance in
the interests of good Lisp programming style.

Regards,
Adam
From: Paul Dietz
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <3F97F126.4A61BE90@motorola.com>
Adam Warner wrote:

> OK you've made some good points (and I suspect Frode Vatvedt Fjeld would
> now express them the same way. I'm sorry I fought you over this Frode).
> 
> Within reason I am now prepared to ignore harm to CLISP's performance in
> the interests of good Lisp programming style.


BTW, if you are using an implementation that ignores INLINE declarations,
you may be able to get much the same effect with a compiler macro (in
combination with the ordinary function definition).

	Paul
From: Adam Warner
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <pan.2003.10.23.23.37.25.833000@consulting.net.nz>
Hi Paul Dietz,

> BTW, if you are using an implementation that ignores INLINE declarations,
> you may be able to get much the same effect with a compiler macro (in
> combination with the ordinary function definition).

Superb! Even though compiler macros can still be ignored by an
implementation CLISP does expand them for compiled code.

(defmacro cs-macro (&rest args)
  `(concatenate 'string ,@args))

(declaim (inline cs-fn))
(defun cs-fn (&rest args)
  (apply #'concatenate 'string args))

(define-compiler-macro cs-fn (&rest args)
  `(concatenate 'string ,@args))

The (disassemble '(cs-macro "a" "b")) and (disassemble '(cs-fn "a" "b"))
byte code is now an identical 5 instructions:
0     (const&push 0)                      ; string
1     (const&push 1)                      ; "a"
2     (const&push 2)                      ; "b"
3     (callsr 2 37)                       ; concatenate
6     (skip&ret 1)

So function expressiveness is still possible while preserving compile-time
speed by code rewriting when it is applicable.

When there is no need to capture and operate upon the &whole form argument
it appears the body of a compiler macro can be written identically to the
body of a standard macro (as I have done here).

Regards,
Adam
From: Frode Vatvedt Fjeld
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <2hznfsicss.fsf@vserver.cs.uit.no>
Adam Warner <······@consulting.net.nz> writes:

> I do not have to justify every minutia of my coding decisions.

So why do it? I was merely offering my perspective, free of charge,
obligations, insults, or what have you. However I see in the next
posts that after you actually did put forward your technical
arguments, your misconception was cleared up. So something good came
out of this after all :-)

-- 
Frode Vatvedt Fjeld
From: ···@afghan.dogpound
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <874qxzb73b.fsf@afghan.dogpound>
Frode Vatvedt Fjeld <······@cs.uit.no> writes:

> ·······@nada.kth.se (Bj�rn Lindberg) writes:
> 
> > Why? He seems to only want cs to be an alias of concatenate 'string,
> > which to me looks like a good use for a macro. I could be wrong
> > though.
> 
> It's got a functional interface, so use a function. Using macros like
> this, more or less as text substitution, is a bad habit one learns as
> a C programmer, I think.

One of the reasons I love Lisp is that I can do anything I damn well
please with it. So that means I generally disregard statements like
that, which don't provide any reason why it is a bad habit, only that
it is one.
From: Pascal Bourguignon
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <871xt9i7vd.fsf@thalassa.informatimago.com>
Adam Warner <······@consulting.net.nz> writes:
> >   (format t "~{~S~^:~}" list)

> I suspect this is the best LOOP that can be constructed:
> 
> (loop for item in list
>       for first = t then nil
>       if first do (format t "~S" item)
>       else do (format t ":~S" item))

If you don't want to use the simple format, you should rather avoid it
in the loop.

(when list
  (loop initially (princ (car list))
        for item in (cdr list)
        do (princ ":") (princ item) ))



-- 
__Pascal_Bourguignon__
http://www.informatimago.com/
Do not adjust your mind, there is a fault in reality.
Lying for having sex or lying for making war?  Trust US presidents :-(
From: Lowell
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <bn0cpn$gs8$1@mughi.cs.ubc.ca>
Wow! Finally something that I can understand! Not that there's anything 
wrong with the other answers, they may be more concise, but they are 
beyond my loop and format understanding right now. Back to the books...

Pascal Bourguignon wrote:
> Adam Warner <······@consulting.net.nz> writes:
> 
>>>  (format t "~{~S~^:~}" list)
> 
> 
>>I suspect this is the best LOOP that can be constructed:
>>
>>(loop for item in list
>>      for first = t then nil
>>      if first do (format t "~S" item)
>>      else do (format t ":~S" item))
> 
> 
> If you don't want to use the simple format, you should rather avoid it
> in the loop.
> 
> (when list
>   (loop initially (princ (car list))
>         for item in (cdr list)
>         do (princ ":") (princ item) ))
> 
> 
> 
From: Ivan Boldyrev
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <9tia61x5av.ln2@ibhome.cgitftp.uiggm.nsc.ru>
On 8536 day of my life Adam Warner wrote:
> Hi Frode Vatvedt Fjeld,
>>   (format t "~{~S~^:~}" list)
>
> I suspect this is the best LOOP that can be constructed:
>
> (loop for item in list
>       for first = t then nil
>       if first do (format t "~S" item)
>       else do (format t ":~S" item))

(loop for item in list
      for dummy = (format t "~S" item) then (format t ":~S" item))

Two-liner :)

P.S.  I spent this Sunday learning LOOP macro, so I am LOOP guru until
I forget something tomorow :) There is advantage of my location: it is
late evening in Berdsk, while it's mornig or afternoon in locations of
most of c.l.l readers :)

-- 
Ivan Boldyrev

                                        | recursion, n:
                                        |       See recursion
From: Thomas A. Russ
Subject: Re: what's the best way to do this?
Date: 
Message-ID: <ymismlng6b8.fsf@sevak.isi.edu>
Lowell <······@cs.ubc.ca> writes:

> 
> I want to print the contents of a list, with colons in between each pair 
> of items. I was hoping that there was a simple way I could do this with 
> the loop macro. Is there?
> 
> Lowell

You know, I interpreted this request a bit differently.  I thought what
was wanted was:

(a b c d) =>  a:b c:d 

Fortunately, this can also be easily done with format:

 (format t "~{~A:~A~^ ~}" my-list)

The list iterator in format is flexible enough to be able to consume
more than one item from the list at each iteration.

-- 
Thomas A. Russ,  USC/Information Sciences Institute