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
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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.
>
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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)))
>
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)))
>
[ 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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
···@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)))
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
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
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))
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
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
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
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
> 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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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.
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
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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 :-(
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
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
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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'
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
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
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
>
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
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
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
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
·······@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
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
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
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
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.
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
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
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
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
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.
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 :-(
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) ))
>
>
>
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
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