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

Idiom for gathering pairs from a list?

21 views
Skip to first unread message

bradb

unread,
Oct 23, 2006, 10:46:38 AM10/23/06
to
I'm using CL-PPCRE, and some functions return lists of start and end
matches, so a return might be
(0 2 4 7 10 15), three matches.
Right now I loop over the matches like
(loop :for match :on (all-matches scanner text :start start) :by
#'cddr
:do (let ((start (first match))
(end (second match)))
(subseq text start end))

Is there a nicer way to gather the pairs than that?

Cheers
Brad

Zach Beane

unread,
Oct 23, 2006, 10:58:09 AM10/23/06
to
"bradb" <brad.be...@gmail.com> writes:

LOOP destructures. Try this:

(loop for (start end) on (all-matches ...) by #'cddr do ...)

Zach


bradb

unread,
Oct 23, 2006, 11:16:02 AM10/23/06
to
Ah, that is much much nicer. It is a shame that loop doesn't defualt
to looping by the natural size of the destructure, so you don't need
the BY #'CDDR.

Also, to really start a hot thread,
(loop :for (start end) :on (....) :do) ; keywords
(loop for (start end) on (...) do) ; no keywords
which is better and why? :-)

Brad

Pascal Bourguignon

unread,
Oct 23, 2006, 11:22:13 AM10/23/06
to
"bradb" <brad.be...@gmail.com> writes:

> Zach Beane wrote:
>> "bradb" <brad.be...@gmail.com> writes:
>>
>> > I'm using CL-PPCRE, and some functions return lists of start and end
>> > matches, so a return might be
>> > (0 2 4 7 10 15), three matches.
>> > Right now I loop over the matches like
>> > (loop :for match :on (all-matches scanner text :start start) :by
>> > #'cddr
>> > :do (let ((start (first match))
>> > (end (second match)))
>> > (subseq text start end))
>> >
>> > Is there a nicer way to gather the pairs than that?
>>
>> LOOP destructures. Try this:
>>
>> (loop for (start end) on (all-matches ...) by #'cddr do ...)
>>
>> Zach
> Ah, that is much much nicer. It is a shame that loop doesn't defualt
> to looping by the natural size of the destructure, so you don't need
> the BY #'CDDR.

(defmacro loop* (&rest stuff)
...
:for ,destructuring-stuff :on ,list by (lambda (list)
(nth-cdr ,(length destructuring-stuff)

> Also, to really start a hot thread,
> (loop :for (start end) :on (....) :do) ; keywords
> (loop for (start end) on (...) do) ; no keywords
> which is better and why? :-)
>
> Brad
>

--
__Pascal Bourguignon__ http://www.informatimago.com/

In a World without Walls and Fences,
who needs Windows and Gates?

Pascal Bourguignon

unread,
Oct 23, 2006, 11:27:20 AM10/23/06
to
"bradb" <brad.be...@gmail.com> writes:

> Zach Beane wrote:
>> "bradb" <brad.be...@gmail.com> writes:
>>
>> > I'm using CL-PPCRE, and some functions return lists of start and end
>> > matches, so a return might be
>> > (0 2 4 7 10 15), three matches.
>> > Right now I loop over the matches like
>> > (loop :for match :on (all-matches scanner text :start start) :by
>> > #'cddr
>> > :do (let ((start (first match))
>> > (end (second match)))
>> > (subseq text start end))
>> >
>> > Is there a nicer way to gather the pairs than that?
>>
>> LOOP destructures. Try this:
>>
>> (loop for (start end) on (all-matches ...) by #'cddr do ...)
>>
>> Zach
> Ah, that is much much nicer. It is a shame that loop doesn't defualt
> to looping by the natural size of the destructure, so you don't need
> the BY #'CDDR.

It's but a defmacro away:

(defmacro loop* (&rest stuff)
...

`(cl:loop


...
:for ,destructuring-stuff :on ,list

:by (lambda (list) (nthcdr ,(length destructuring-stuff) list))
...))

> Also, to really start a hot thread,
> (loop :for (start end) :on (....) :do) ; keywords
> (loop for (start end) on (...) do) ; no keywords
> which is better and why? :-)

Try this at your REPL to see which is better, and why.

http://paste.lisp.org/display/28420


--
__Pascal Bourguignon__ http://www.informatimago.com/

In a World without Walls and Fences,
who needs Windows and Gates?

"bradb" <brad.be...@gmail.com> writes:

Bill Atkins

unread,
Oct 23, 2006, 1:55:26 PM10/23/06
to
Pascal Bourguignon <p...@informatimago.com> writes:

> Try this at your REPL to see which is better, and why.
>
> http://paste.lisp.org/display/28420

So just treat LOOP keywords as if they were in COMMON-LISP and expect
the same mayhem you would from exporting your own DEFUN.

Pascal Bourguignon

unread,
Oct 23, 2006, 2:47:35 PM10/23/06
to
Bill Atkins <atk...@rpi.edu> writes:

No it's not possible, since COMMON-LISP doesn't export WHILE.

And it's much simplier to use keywords (from the KEYWORD package) than
to use SHADOW at the right places and qualify UTILITY:WHILE.

--
__Pascal Bourguignon__ http://www.informatimago.com/

"A TRUE Klingon warrior does not comment his code!"

Kalle Olavi Niemitalo

unread,
Oct 23, 2006, 5:02:16 PM10/23/06
to
Pascal Bourguignon <p...@informatimago.com> writes:

> "bradb" <brad.be...@gmail.com> writes:
>> Also, to really start a hot thread,
>> (loop :for (start end) :on (....) :do) ; keywords
>> (loop for (start end) on (...) do) ; no keywords
>> which is better and why? :-)
>
> Try this at your REPL to see which is better, and why.
>
> http://paste.lisp.org/display/28420

That code defines a package EXAMPLE2, causes WHILE to be interned
to it by using it as a loop keyword, and then tries to use the
MYLOOP package which exports another WHILE:

* (use-package "MYLOOP")

debugger invoked on a SB-INT:NAME-CONFLICT in thread #<THREAD "initial thread" {9003399}>:
USE-PACKAGE #<PACKAGE "MYLOOP"> causes name-conflicts in
#<PACKAGE "EXAMPLE2"> between the following symbols:
MYLOOP:WHILE, WHILE
See also:
The ANSI Standard, Section 11.1.1.2.5

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
0: [RESOLVE-CONFLICT] Resolve conflict.
1: [ABORT ] Exit debugger, returning to top level.

(SB-INT:NAME-CONFLICT #<PACKAGE "EXAMPLE2"> USE-PACKAGE #<PACKAGE "MYLOOP">)
0] 0

Select a symbol to be made accessible in package EXAMPLE2:
1. MYLOOP:WHILE
2. WHILE

Enter an integer (between 1 and 2): 1

T
*

Resolving the conflict doesn't seem very difficult or cumbersome;
prepending colons to all loop keywords would require more typing.
And if this were in a program rather than in the REPL, then you'd
surely avoid USE-PACKAGE and instead put MYLOOP in the DEFPACKAGE
form you already had for EXAMPLE2.

There are other loop keywords for which you could construct
similar conflicts; for example SUM. That one is also more likely
to occur as the name of a variable than WHILE is. Which you
cannot solve by using keywords instead.

Pascal Bourguignon

unread,
Oct 23, 2006, 5:41:22 PM10/23/06
to
Kalle Olavi Niemitalo <k...@iki.fi> writes:
> There are other loop keywords for which you could construct
> similar conflicts; for example SUM. That one is also more likely
> to occur as the name of a variable than WHILE is. Which you
> cannot solve by using keywords instead.

(loop :for i :from 1 :to 100 :sum i) ; perfectly solved, thank you.

--
__Pascal Bourguignon__ http://www.informatimago.com/

Until real software engineering is developed, the next best practice
is to develop with a dynamic system that has extreme late binding in
all aspects. The first system to really do this in an important way
is Lisp. -- Alan Kay

Wade Humeniuk

unread,
Oct 23, 2006, 8:35:16 PM10/23/06
to

As a side note, what is wrong with using cl-ppcre:do-matches or
cl-ppcre:do-matches-as-strings or cl-ppcre:all-matches-as-strings ?

(defun collect-subseqs (text list)
(loop while list collect
(subseq text (pop list) (pop list))))

CL-USER 3 > (collect-subseqs "test 123" '())
NIL

CL-USER 4 > (collect-subseqs "test 123" '(2))
("st 123")

CL-USER 5 > (collect-subseqs "test 123" '(2 7))
("st 12")

CL-USER 6 >

Wade

Rob Warnock

unread,
Oct 23, 2006, 11:45:21 PM10/23/06
to
Pascal Bourguignon <p...@informatimago.com> wrote:
+---------------

| "bradb" <brad.be...@gmail.com> writes:
| > Zach Beane wrote:
| >> "bradb" <brad.be...@gmail.com> writes:
| >> > Is there a nicer way to gather the pairs than that?
| >> LOOP destructures. Try this:
| >> (loop for (start end) on (all-matches ...) by #'cddr do ...)
| > Ah, that is much much nicer. It is a shame that loop doesn't defualt
| > to looping by the natural size of the destructure, so you don't need
| > the BY #'CDDR.
|
| (defmacro loop* (&rest stuff)
| ...
| :for ,destructuring-stuff :on ,list by (lambda (list)
| (nth-cdr ,(length
| destructuring-stuff)
+---------------

The problem with any such automatic sizing is LOOPs like this:

(loop for (a b c . rest) on list by #'cdddr ...)

or even this:

(flet ((stepper (list)
(case (car list)
((:one) (cddr list))
((:two) (cdddr list))
((:three) (cdddr list))
(otherwise (cdr list)))))
(loop for (key a b c) on list by #'stepper ...))

which can parse lists like this:

(:one 123 :two 234 453 :three 7 5 8 :special :other 99 22 :two 34 54)


-Rob

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

Kalle Olavi Niemitalo

unread,
Oct 24, 2006, 4:48:14 PM10/24/06
to
Pascal Bourguignon <p...@informatimago.com> writes:

> Kalle Olavi Niemitalo <k...@iki.fi> writes:
>> There are other loop keywords for which you could construct
>> similar conflicts; for example SUM. That one is also more likely
>> to occur as the name of a variable than WHILE is. Which you
>> cannot solve by using keywords instead.
>
> (loop :for i :from 1 :to 100 :sum i) ; perfectly solved, thank you.

That uses neither SUM nor :SUM as the name of a variable.

Thomas A. Russ

unread,
Oct 24, 2006, 4:45:48 PM10/24/06
to
Pascal Bourguignon <p...@informatimago.com> writes:

> Kalle Olavi Niemitalo <k...@iki.fi> writes:
> > There are other loop keywords for which you could construct
> > similar conflicts; for example SUM. That one is also more likely
> > to occur as the name of a variable than WHILE is. Which you
> > cannot solve by using keywords instead.
>
> (loop :for i :from 1 :to 100 :sum i) ; perfectly solved, thank you.

But it still doesn't solve:

(let ((sum (loop :for ...)))
(print sum))

(use "SOME-PACKAGE-EXPORTING-SUM")


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

Pascal Bourguignon

unread,
Oct 24, 2006, 7:58:41 PM10/24/06
to

The fundamental difference, is that you can rename sum either in your
let, or in the SOME-PACKAGE-EXPORTING-SUM, but you cannot rename the
LOOP keywords.

--
__Pascal Bourguignon__ http://www.informatimago.com/

"You question the worthiness of my code? I should kill you where you
stand!"

WJ

unread,
Feb 24, 2011, 11:30:57 AM2/24/11
to
bradb wrote:

Using Scheme:

(define str "DOLL IS A COB TOP LONG")
(define ind '(18 20 15 17 4 8 10 13 1 3))
(define (subs str lst) (apply substring str (take lst 2)))

(let recur ((lst ind))
(if (pair? lst)
(begin (display (subs str lst))
(recur (cddr lst)))))

==> LOOP IS COBOL

WJ

unread,
May 5, 2011, 1:13:45 PM5/5/11
to
bradb wrote:

Arc:

arc> (= str "DOLL? IS A COB TOP LONG"?)


"DOLL IS A COB TOP LONG"

arc> (string (map [apply cut str _] (pair '(18 20 15 17 4 8 10 13 1 3))))
"LOOP IS COBOL"

0 new messages