Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Most impressive examples of the LOOP macro

135 views
Skip to first unread message

Tron3k

unread,
Jul 19, 2005, 7:04:03 PM7/19/05
to
Greetings fellow Common Lispers.

As some of you may know I am developing a new variant of Lisp. I am
currently figuring out iteration constructs. In particular, I am
experimenting with a method of iteration that iterates in parallel over
several lazy sequences, stopping when any of them terminates. I have
found this useful to replace several uses of the LOOP macro in my code.
However, I know the LOOP macro is too powerful for any one man to
comprehend. Hence, I request that you post the most impressive,
succinct, and elegant examples of the LOOP macro in action, so that I
can use them as goalposts for my language's iteration constructs.

Here's one of mine (I invented this one myself):

; Prints the first 16 rows of Pascal's triangle
; not tested, I'm writing it from memory right here!
(loop repeat 16
for list = '(1) then (mapcar #'+ (cons 0 list) (append list
'(0)))
do (format t "~{~6D~^,~}~%" list))

That's definitely one of the most beautiful pieces of code I've ever
written. I wrote it for a programming language comparison contest, and
blew every other language out of the water, except Mathematica, of
course. ;-)

Tron3k

Pascal Costanza

unread,
Jul 19, 2005, 7:51:50 PM7/19/05
to
Tron3k wrote:
> Greetings fellow Common Lispers.
>
> As some of you may know I am developing a new variant of Lisp. I am
> currently figuring out iteration constructs. In particular, I am
> experimenting with a method of iteration that iterates in parallel over
> several lazy sequences, stopping when any of them terminates. I have
> found this useful to replace several uses of the LOOP macro in my code.
> However, I know the LOOP macro is too powerful for any one man to
> comprehend. Hence, I request that you post the most impressive,
> succinct, and elegant examples of the LOOP macro in action, so that I
> can use them as goalposts for my language's iteration constructs.

These requests have been made in the past for some other projects.
Googling in the archives of comp.lang.lisp should give you some ideas.


Pascal

--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/

Matthias Buelow

unread,
Jul 19, 2005, 8:21:49 PM7/19/05
to
"Tron3k" <tro...@gmail.com> writes:

>That's definitely one of the most beautiful pieces of code I've ever
>written.

Warning: slippery slope.

mkb.

Tron3k

unread,
Jul 20, 2005, 12:37:32 AM7/20/05
to
Pascal Costanza wrote:
> Tron3k wrote:
> > Greetings fellow Common Lispers.
> >
> > As some of you may know I am developing a new variant of Lisp. I am
> > currently figuring out iteration constructs. In particular, I am
> > experimenting with a method of iteration that iterates in parallel over
> > several lazy sequences, stopping when any of them terminates. I have
> > found this useful to replace several uses of the LOOP macro in my code.
> > However, I know the LOOP macro is too powerful for any one man to
> > comprehend. Hence, I request that you post the most impressive,
> > succinct, and elegant examples of the LOOP macro in action, so that I
> > can use them as goalposts for my language's iteration constructs.
>
> These requests have been made in the past for some other projects.
> Googling in the archives of comp.lang.lisp should give you some ideas.

Thanks. I did, in fact, google for cool Lisp snippets before posting
this and found some interesting ones such as the one that prints the
Mandelbrot set using ASCII characters. I just thought that it would be
fun to have a thread for everyone to share the cool snippets they have
tucked away ... I've done this on other forums and people usually enjoy
it.

Tron3k

unread,
Jul 20, 2005, 12:38:35 AM7/20/05
to

???

Paolo Amoroso

unread,
Jul 20, 2005, 3:38:45 AM7/20/05
to
"Tron3k" <tro...@gmail.com> writes:

> currently figuring out iteration constructs. In particular, I am
> experimenting with a method of iteration that iterates in parallel over
> several lazy sequences, stopping when any of them terminates. I have
> found this useful to replace several uses of the LOOP macro in my code.

I also have a way of replacing uses of LOOP: MACROEXPAND.


Paolo
--
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools:
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface

Timofei Shatrov

unread,
Jul 20, 2005, 4:42:13 AM7/20/05
to
On 19 Jul 2005 16:04:03 -0700, "Tron3k" <tro...@gmail.com> tried to
confuse everyone with this message:

>Greetings fellow Common Lispers.
>
>As some of you may know I am developing a new variant of Lisp. I am
>currently figuring out iteration constructs. In particular, I am
>experimenting with a method of iteration that iterates in parallel over
>several lazy sequences, stopping when any of them terminates. I have
>found this useful to replace several uses of the LOOP macro in my code.
>However, I know the LOOP macro is too powerful for any one man to
>comprehend. Hence, I request that you post the most impressive,
>succinct, and elegant examples of the LOOP macro in action, so that I
>can use them as goalposts for my language's iteration constructs.

Here is one neat loop I wrote. Not very efficient, though...

;Continous fractions: 47/350 -> (0 (1 3) (4 2 8 5 7 1))
(defun contdivstuff (a b &key (base 10))
(multiple-value-bind (whole r) (floor (/ a b))
(loop for tr = (* base r) then (* base (- tr (floor tr)))
for tail = (member tr past)
until tail
collecting tr into past
finally (return (list whole (mapcar #'floor (ldiff past tail))
(mapcar #'floor tail))))))

--
|a\o/r|,-------------.,---------- Timofei Shatrov aka Grue ------------.
| m"a ||FC AMKAR PERM|| mail: grue at mail.ru http://grue3.tripod.com |
| k || PWNZ J00 || Kingdom of Loathing: Grue3 lvl 18 Seal Clubber |
`-----'`-------------'`-------------------------------------------[4*72]

Tron3k

unread,
Jul 20, 2005, 10:13:50 AM7/20/05
to
Paolo Amoroso wrote:
> "Tron3k" <tro...@gmail.com> writes:
>
> > currently figuring out iteration constructs. In particular, I am
> > experimenting with a method of iteration that iterates in parallel over
> > several lazy sequences, stopping when any of them terminates. I have
> > found this useful to replace several uses of the LOOP macro in my code.
>
> I also have a way of replacing uses of LOOP: MACROEXPAND.

Its expansion is hideous, but I don't think that's what you meant.

You're saying that it's stupid to hate a tool if it works. You're
fitting me into your pre-existing archetype of the mindless anti-LOOP
bigot. Well, there are reasons I'm not going to translate all the code
for LOOP into my new Lisp. First of all, it would be hard to get right.
Second of all, I'm trying to make this language simple to implement,
since as PG says, source code is often the best spec. So I'm trying to
find a good combination of simple but powerful constructs that are
equivalent in expressivity to LOOP.

Pascal Costanza

unread,
Jul 20, 2005, 10:24:22 AM7/20/05
to

I had your more specific request in mind, wrt examples using LOOP. There
were a number of examples posted in conjunction with LinJ.

Tron3k

unread,
Jul 20, 2005, 10:37:00 AM7/20/05
to

Paolo Amoroso

unread,
Jul 20, 2005, 10:42:30 AM7/20/05
to
"Tron3k" <tro...@gmail.com> writes:

> Paolo Amoroso wrote:
[...]


>> I also have a way of replacing uses of LOOP: MACROEXPAND.
>
> Its expansion is hideous, but I don't think that's what you meant.
>
> You're saying that it's stupid to hate a tool if it works. You're
> fitting me into your pre-existing archetype of the mindless anti-LOOP
> bigot. Well, there are reasons I'm not going to translate all the code

No.

Peter Seibel

unread,
Jul 20, 2005, 12:56:29 PM7/20/05
to
"Tron3k" <tro...@gmail.com> writes:

> Here's one of mine (I invented this one myself):
>
> ; Prints the first 16 rows of Pascal's triangle
> ; not tested, I'm writing it from memory right here!
> (loop repeat 16
> for list = '(1) then (mapcar #'+ (cons 0 list) (append list
> '(0)))
> do (format t "~{~6D~^,~}~%" list))
>
> That's definitely one of the most beautiful pieces of code I've ever
> written. I wrote it for a programming language comparison contest,
> and blew every other language out of the water, except Mathematica,
> of course. ;-)

Hmmm. I'm not sure any code that repeatedly APPENDs to the end of a
growing list can be all that elegant. If you're into this sort of
thin, both the versions below, while slightly longer in terms of
number of characters than yours, are, I'd argue, algorithmically more
elegant:

(loop repeat 16 for list = '(1)

then (maplist #'(lambda (cons) (+ (car cons) (or (cadr cons) 0))) (cons 0 list))


do (format t "~{~6D~^,~}~%" list))

(loop repeat 16 for list = '(1)
then (maplist #'(lambda (cons) (apply #'+ (ldiff cons (cddr cons)))) (cons 0 list))


do (format t "~{~6D~^,~}~%" list))

-Peter

--
Peter Seibel * pe...@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp * http://www.gigamonkeys.com/book/

Peter Lewerin

unread,
Jul 20, 2005, 6:26:05 PM7/20/05
to
Peter Seibel <pe...@gigamonkeys.com> wrote:

> Hmmm. I'm not sure any code that repeatedly APPENDs to the end of a
> growing list can be all that elegant. If you're into this sort of
> thin, both the versions below, while slightly longer in terms of
> number of characters than yours, are, I'd argue, algorithmically more
> elegant:
>
> (loop repeat 16 for list = '(1)
> then (maplist #'(lambda (cons) (+ (car cons) (or (cadr cons) 0))) (cons 0 list))
> do (format t "~{~6D~^,~}~%" list))
>
> (loop repeat 16 for list = '(1)
> then (maplist #'(lambda (cons) (apply #'+ (ldiff cons (cddr cons)))) (cons 0 list))
> do (format t "~{~6D~^,~}~%" list))

Maybe even

(loop repeat 16
for list = '(1)

then (cons 1 (loop for (a b) on list
collecting (+ a (or b 0))))
do (format t "~&~{~6D~^,~}~%" list))

Tron3k

unread,
Jul 20, 2005, 9:50:01 PM7/20/05
to
Peter Seibel wrote:
> "Tron3k" <tro...@gmail.com> writes:
>
> > Here's one of mine (I invented this one myself):
> >
> > ; Prints the first 16 rows of Pascal's triangle
> > ; not tested, I'm writing it from memory right here!
> > (loop repeat 16
> > for list = '(1) then (mapcar #'+ (cons 0 list) (append list
> > '(0)))
> > do (format t "~{~6D~^,~}~%" list))
> >
> > That's definitely one of the most beautiful pieces of code I've ever
> > written. I wrote it for a programming language comparison contest,
> > and blew every other language out of the water, except Mathematica,
> > of course. ;-)
>
> Hmmm. I'm not sure any code that repeatedly APPENDs to the end of a
> growing list can be all that elegant. If you're into this sort of
> thin, both the versions below, while slightly longer in terms of
> number of characters than yours, are, I'd argue, algorithmically more
> elegant:
>
> (loop repeat 16 for list = '(1)
> then (maplist #'(lambda (cons) (+ (car cons) (or (cadr cons) 0))) (cons 0 list))
> do (format t "~{~6D~^,~}~%" list))
>
> (loop repeat 16 for list = '(1)
> then (maplist #'(lambda (cons) (apply #'+ (ldiff cons (cddr cons)))) (cons 0 list))
> do (format t "~{~6D~^,~}~%" list))

Yeah, I know. The contest was to create the shortest code though. :-)

Tron3k

unread,
Jul 20, 2005, 9:53:53 PM7/20/05
to
Paolo Amoroso wrote:
> "Tron3k" <tro...@gmail.com> writes:
>
> > Paolo Amoroso wrote:
> [...]
> >> I also have a way of replacing uses of LOOP: MACROEXPAND.
> >
> > Its expansion is hideous, but I don't think that's what you meant.
> >
> > You're saying that it's stupid to hate a tool if it works. You're
> > fitting me into your pre-existing archetype of the mindless anti-LOOP
> > bigot. Well, there are reasons I'm not going to translate all the code
>
> No.

Oh, so you were just wasting everyone's time with a thoroughly useless
comment. Ok then.

Don Geddis

unread,
Jul 20, 2005, 7:38:34 PM7/20/05
to
"Tron3k" <tro...@gmail.com> wrote on 20 Jul 2005 07:1:
> Well, there are reasons I'm not going to translate all the code for LOOP
> into my new Lisp. First of all, it would be hard to get right.

True. Yet many CL programmers find it valuable that CL implementors spend
this effort. I wonder if the programming community for your new language
will be as forgiving of you not bothering to put forth the effort.

> Second of all, I'm trying to make this language simple to implement

More and more, it sure sounds like you would be happier in the Scheme
community. They share much of your aesthetic sense. For example: Lisp-1,
small language spec, simple to implement, etc.

You sure don't sound like someone trying to improve Common Lisp. You sound
like a Scheme guy who is trying to convert the "enemy".

> since as PG says, source code is often the best spec.

Leaving aside whether Paul Graham is the Prophet of Lisp, such that his
every word must become our law ... how is this even related? "Source code
being the best spec" means that a sufficiently powerful language would allow
you to express most of what is usually in documentation, directly in the
language itself.

How does that have anything to do with whether the language is easy to
implement or not?

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
Writing about music is like dancing about architecture.

Paolo Amoroso

unread,
Jul 21, 2005, 4:45:41 AM7/21/05
to
"Tron3k" <tro...@gmail.com> writes:

>> > Paolo Amoroso wrote:
>> [...]
>> >> I also have a way of replacing uses of LOOP: MACROEXPAND.

[...]


> Oh, so you were just wasting everyone's time with a thoroughly useless
> comment. Ok then.

It was a joke. As for wasting everyone's time, everyone can decide
for himself/herself.

WJ

unread,
Feb 28, 2011, 2:34:30 PM2/28/11
to
Tron3k wrote:

Guile Scheme:

(use-modules (ice-9 format)) ; CL-style format

(let recur ((lst '(1))) (and (< (length lst) 17)
(format #t "~{~6D~^,~}~%" lst)
(recur (map + (cons 0 lst) (append lst '(0))))))

jos...@lisp.de

unread,
Feb 28, 2011, 4:48:46 PM2/28/11
to

Common Lisp:

(defmacro llet (name vars &body body)
(let ((start-tag (gentemp)))
`(prog ,vars
,start-tag
(macrolet
((,name (&rest args)
(append '(progn)
(loop for arg in args and var in ',vars
collect `(setq ,(if (consp var)
(first var)
var)
,arg))
(list (list 'go ',start-tag)))))
(locally ,@body)))))

(llet recur ((list '(1)))
(when (< (length list) 17)


(format t "~{~6D~^,~}~%" list)

(recur (mapcar '+ (cons 0 list) (append list '(0))))))

yuridichesky

unread,
Mar 1, 2011, 10:24:30 AM3/1/11
to

jos...@lisp.de wrote:
[snip]

>
> (defmacro llet (name vars &body body)
[snip]

>
> (llet recur ((list '(1)))
> (when (< (length list) 17)
> (format t "~{~6D~^,~}~%" list)
> (recur (mapcar '+ (cons 0 list) (append list '(0))))))

llet looks exactly like Scheme's named let. Cool, that's what I miss
in CL. Thanks.

- Yuri

Marco Antoniotti

unread,
Mar 1, 2011, 12:20:51 PM3/1/11
to

Actually, it should expand into a LABELS to approach Scheme's
semantics.

(defmacro nlet (name vars &body body)
`(labels ((,name ,(mapcar 'first vars) ,@body))
(,name ,@(mapcar 'second vars))))

It is an old macro. Older than the original thread the SLDJ troll
responded to :)

cheers
--
MA

jos...@lisp.de

unread,
Mar 1, 2011, 12:39:42 PM3/1/11
to

The idea was that it provides kind of a LOOP without need to support
TCO,
Thus no LABELS.

yuridichesky

unread,
Mar 1, 2011, 2:18:13 PM3/1/11
to

jos...@lisp.de wrote:
> The idea was that it provides kind of a LOOP without need to support
> TCO,
> Thus no LABELS.

Right, this is what I like the most.

- Yuri

Marco Antoniotti

unread,
Mar 1, 2011, 4:20:09 PM3/1/11
to

Well, this day and age, I assume a good CL implementation *will*
provide TCO. Besides, while it is true that Scheme named let is used
mostly for loops, you could use it in non-TCO settings.

(let fact ((x 4))
(if (= x 0)
1
(* x (fact (- x 1)))))

The above is Scheme.

Cheers
--
Marco

jos...@lisp.de

unread,
Mar 1, 2011, 4:57:02 PM3/1/11
to

Does ABCL on the JVM??? Interpreted CLISP?

Also: it is possible that your code will be TCO, but not necessarily.
TCO in CL is tricky. It requires that the compiler runs in the right
mode, a compiler is used (does any CL interpreter do TCO) and a few
restrictions are not violated (say, dynamic bindings).

Carlos

unread,
Mar 1, 2011, 5:52:20 PM3/1/11
to
["jos...@lisp.de" <jos...@lisp.de>, 2011-03-01 13:57]

> > > >  (defmacro nlet (name vars &body body)
> > > >    `(labels ((,name ,(mapcar 'first vars) ,@body))
> > > >        (,name ,@(mapcar 'second vars))))
> >
> > > > It is an old macro.  Older than the original thread the SLDJ
> > > > troll responded to :)
> >
> > > > cheers
> > > > --
> > > > MA
> >
> > > The idea was that it provides kind of a LOOP without need to
> > > support TCO,
> > > Thus no LABELS.
> >
> > Well, this day and age, I assume a good CL implementation *will*
> > provide TCO.
>
> Does ABCL on the JVM??? Interpreted CLISP?

CLISP does optimize recursive tail calls (but no other tail calls).
--

Marco Antoniotti

unread,
Mar 1, 2011, 6:08:17 PM3/1/11
to

Fine. I'll grant you all of that. Yet, Scheme "named let" implies
LABELS semantics.

Cheers
--
Marco

jos...@lisp.de

unread,
Mar 1, 2011, 6:34:15 PM3/1/11
to

The Interpreter, the Compiler or both?

> --

WJ

unread,
Mar 1, 2011, 10:00:53 PM3/1/11
to
Tron3k wrote:

> Greetings fellow Common Lispers.
>
> As some of you may know I am developing a new variant of Lisp. I am
> currently figuring out iteration constructs. In particular, I am
> experimenting with a method of iteration that iterates in parallel over
> several lazy sequences, stopping when any of them terminates. I have
> found this useful to replace several uses of the LOOP macro in my code.
> However, I know the LOOP macro is too powerful for any one man to
> comprehend. Hence, I request that you post the most impressive,
> succinct, and elegant examples of the LOOP macro in action, so that I
> can use them as goalposts for my language's iteration constructs.
>
> Here's one of mine (I invented this one myself):
>
> ; Prints the first 16 rows of Pascal's triangle
> ; not tested, I'm writing it from memory right here!
> (loop repeat 16

> for list = '(1) then (mapcar #'+ (cons 0 list) (append list
> '(0)))


> do (format t "~{~6D~^,~}~%" list))
>
> That's definitely one of the most beautiful pieces of code I've ever
> written. I wrote it for a programming language comparison contest, and
> blew every other language out of the water, except Mathematica, of
> course. ;-)

Really? It didn't blow MatzLisp out of the water.

The first 10 rows ouput by your code:

1
1, 1
1, 2, 1
1, 3, 3, 1
1, 4, 6, 4, 1
1, 5, 10, 10, 5, 1
1, 6, 15, 20, 15, 6, 1
1, 7, 21, 35, 35, 21, 7, 1
1, 8, 28, 56, 70, 56, 28, 8, 1
1, 9, 36, 84, 126, 126, 84, 36, 9, 1


The Ruby code and output:

r = [1]
13.times{puts r.map{|n| n.to_s.center 4}.join.center 79
r = ([0]+r).zip(r << 0).map{|a,b| a+b}}


1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1


Much prettier.

jos...@lisp.de

unread,
Mar 2, 2011, 12:48:21 AM3/2/11
to

Common Lisp:


CL-USER 221 > (llet recur ((list '(1)))
(when (< (length list) 12)
(format t "~60:@<~{~5D~^~}~>~%" list)
(recur (mapcar '+ (cons 0 list) (append list
'(0))))))

Carlos

unread,
Mar 2, 2011, 12:56:11 AM3/2/11
to
["jos...@lisp.de" <jos...@lisp.de>, 2011-03-01 15:34]

> > > > Well, this day and age, I assume a good CL implementation *will*
> > > > provide TCO.
> >
> > > Does ABCL on the JVM??? Interpreted CLISP?
> >
> > CLISP does optimize recursive tail calls (but no other tail calls).
>
> The Interpreter, the Compiler or both?

Ah, you are right. The compiler does, but not the interpreter. I had a
misconception about how CLISP worked.
--

yuridichesky

unread,
Mar 2, 2011, 2:04:12 AM3/2/11
to

jos...@lisp.de wrote:
[snip]

> (defmacro llet (name vars &body body)
[snip]

BTW, what does the frist 'l' in llet stand for?

- Yuri

Pascal Costanza

unread,
Mar 2, 2011, 3:23:28 AM3/2/11
to
On 01/03/2011 22:57, jos...@lisp.de wrote:
> On 1 Mrz., 22:20, Marco Antoniotti<marc...@gmail.com> wrote:
>> On Mar 1, 6:39 pm, "jos...@lisp.de"<jos...@lisp.de> wrote:
>>
>>
>>
>>
>>
>>> On Mar 1, 6:20 pm, Marco Antoniotti<marc...@gmail.com> wrote:
>>
>>>> On Mar 1, 4:24 pm, yuridichesky<yuridiche...@gmail.com> wrote:
>>
>>>>> jos...@lisp.de wrote:
>>
>>>>> [snip]
>>
>>>>>> (defmacro llet (name vars&body body)

>>>>> [snip]
>>
>>>>>> (llet recur ((list '(1)))
>>>>>> (when (< (length list) 17)
>>>>>> (format t "~{~6D~^,~}~%" list)
>>>>>> (recur (mapcar '+ (cons 0 list) (append list '(0))))))
>>
>>>>> llet looks exactly like Scheme's named let. Cool, that's what I miss
>>>>> in CL. Thanks.
>>
>>>> Actually, it should expand into a LABELS to approach Scheme's
>>>> semantics.
>>
>>>> (defmacro nlet (name vars&body body)

>>>> `(labels ((,name ,(mapcar 'first vars) ,@body))
>>>> (,name ,@(mapcar 'second vars))))
>>
>>>> It is an old macro. Older than the original thread the SLDJ troll
>>>> responded to :)
>>
>>>> cheers
>>>> --
>>>> MA
>>
>>> The idea was that it provides kind of a LOOP without need to support
>>> TCO,
>>> Thus no LABELS.
>>
>> Well, this day and age, I assume a good CL implementation *will*
>> provide TCO.
>
> Does ABCL on the JVM??? Interpreted CLISP?
>
> Also: it is possible that your code will be TCO, but not necessarily.
> TCO in CL is tricky. It requires that the compiler runs in the right
> mode, a compiler is used (does any CL interpreter do TCO) and a few
> restrictions are not violated (say, dynamic bindings).

Another case where many CL implementations fail is CLOS methods: Since
many implementations use an internal special variable to bind the list
of next methods that call-next-method can invoke, it's likely that TCO
is not possible in cases that you would actually expect it to work. (To
the best of my knowledge, only SBCL gets this one right.)


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

jos...@lisp.de

unread,
Mar 2, 2011, 9:12:25 AM3/2/11
to

I had thought about the 'l' for about a minute.
It is the loop-let... ;-)

0 new messages