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

PCL trash

235 views
Skip to first unread message

WJ

unread,
Mar 3, 2011, 10:53:10 PM3/3/11
to
While dumpster-diving, I found a discarded copy of PCL.*

The book devotes a whole chapter to the COBOLer's delight:
LOOP. Those who aren't comfortable with higher-order functions
are completely dependent upon it.

Using Guile Scheme, I give first the COBOL way as shown in the
book and then the right way.

The low, loopy way:

(loop for i upto 10 collect i)


The high way:

(iota 11)

Another way:

(list-tabulate 11 identity)


The low, loopy way:

(loop repeat 5
for x = 0 then y
for y = 1 then (+ x y)
collect y) ==> (1 2 4 8 16)


The high way:

(map (curry expt 2) (iota 5))
==> (1 2 4 8 16)


The low, loopy way:

(loop for (a nil) in '((1 2) (3 4) (5 6)) collect a) ==> (1 3 5)


The high way:

(map car '((1 2) (3 4) (5 6)))

The low, loopy way:

CL-USER> (loop for (a b) in '((1 2) (3 4) (5 6))
do (format t "a: ~a; b: ~a~%" a b))
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6
NIL


The high way:

(for-each (curry apply format #t "a: ~a; b: ~a~%")
'((1 2) (3 4) (5 6)))

Another way:

guile> (use-modules (ice-9 format))
guile> (format #t "~:{a: ~d; b: ~d~%~}" '((1 2) (3 4) (5 6)))
a: 1; b: 2
a: 3; b: 4
a: 5; b: 6
#t

The low, loopy way:

(loop for (item . rest) on list
do (format t "~a" item)
when rest do (format t ", "))


The high way:

guile> (string-join (map object->string (iota 9)) ", ")
"0, 1, 2, 3, 4, 5, 6, 7, 8"

The low, loopy way:

(defparameter *random* (loop repeat 100 collect (random 10000)))

(loop for i in *random*
counting (evenp i) into evens
counting (oddp i) into odds
summing i into total
maximizing i into max
minimizing i into min
finally (return (list min max total evens odds)))


The high way:

(define *random* (list-tabulate 100 (lambda _ (random 10000))))

(append
(map (rcurry apply *random*) (list min max +))
(map (rcurry count *random*) (list even? odd?)))

==> (283 9896 503380 52 48)

Here are the definitions of curry and rcurry:

(define (curry f . args) (lambda x (apply f (append args x))))
(define (rcurry f . last-args)
(lambda x (apply f (append x last-args))))


(* Poetic license.)

Rainer Joswig

unread,
Mar 4, 2011, 1:57:47 AM3/4/11
to
On 4 Mrz., 04:53, "WJ" <w_a_x_...@yahoo.com> wrote:
> While dumpster-diving, I found a discarded copy of PCL.*

>
> The book devotes a whole chapter to the COBOLer's delight:
> LOOP.  Those who aren't comfortable with higher-order functions
> are completely dependent upon it.
>
> Using Guile Scheme, I give first the COBOL way as shown in the
> book and then the right way.
>
> The low, loopy way:
>
> (loop for i upto 10 collect i)
>
> The high way:
>
> (iota 11)

CL-USER 29 > (iota 11)
(0 1 2 3 4 5 6 7 8 9 10)


>
> Another way:
>
> (list-tabulate 11 identity)
>
> The low, loopy way:
>
> (loop repeat 5
>       for x = 0 then y
>       for y = 1 then (+ x y)
>       collect y) ==> (1 2 4 8 16)
>
> The high way:
>
> (map (curry expt 2) (iota 5))
>   ==> (1 2 4 8 16)

CL-USER 32 > (mapcar (curry 'expt 2) (iota 5))


(1 2 4 8 16)

>
> The low, loopy way:
>
> (loop for (a nil) in '((1 2) (3 4) (5 6)) collect a) ==> (1 3 5)
>
> The high way:
>
> (map car '((1 2) (3 4) (5 6)))

CL-USER 33 > (mapcar 'car '((1 2) (3 4) (5 6)))
(1 3 5)

> The low, loopy way:
>
> CL-USER> (loop for (a b) in '((1 2) (3 4) (5 6))
>             do (format t "a: ~a; b: ~a~%" a b))
> a: 1; b: 2
> a: 3; b: 4
> a: 5; b: 6
> NIL
>
> The high way:
>
> (for-each (curry apply format #t "a: ~a; b: ~a~%")
>           '((1 2) (3 4) (5 6)))

CL-USER 34 > (mapc (curry 'apply 'format t "a: ~a; b: ~a~%")


'((1 2) (3 4) (5 6)))

a: 1; b: 2
a: 3; b: 4
a: 5; b: 6

((1 2) (3 4) (5 6))

> Another way:
>
> guile> (use-modules (ice-9 format))
> guile> (format #t "~:{a: ~d; b: ~d~%~}" '((1 2) (3 4) (5 6)))
> a: 1; b: 2
> a: 3; b: 4
> a: 5; b: 6
> #t
>
> The low, loopy way:
>
> (loop for (item . rest) on list
>     do (format t "~a" item)
>     when rest do (format t ", "))
>
> The high way:
>
> guile> (string-join (map object->string (iota 9)) ", ")
> "0, 1, 2, 3, 4, 5, 6, 7, 8"

CL-USER 40 > (join 'string (mapcar 'princ-to-string (iota 9)) ", ")

> The low, loopy way:
>
> (defparameter *random* (loop repeat 100 collect (random 10000)))
>
> (loop for i in *random*
>    counting (evenp i) into evens
>    counting (oddp i) into odds
>    summing i into total
>    maximizing i into max
>    minimizing i into min
>    finally (return (list min max total evens odds)))
>
> The high way:
>
> (define *random* (list-tabulate 100 (lambda _ (random 10000))))
>
> (append
>   (map (rcurry apply *random*) (list min max +))
>   (map (rcurry count *random*) (list even? odd?)))
>
>   ==> (283 9896 503380 52 48)
>
> Here are the definitions of curry and rcurry:
>
> (define (curry f . args) (lambda x (apply f (append args x))))
> (define (rcurry f . last-args)
>   (lambda x (apply f (append x last-args))))

CL-USER 48 > (let ((rlist (list-tabulate 100 (lambda (x) (random
10000)))))
(append (mapcar (rcurry 'apply rlist) (list 'min 'max
'+))
(mapcar (rcurry 'count rlist) (list 'evenp
'oddp))))
(49 9804 522193 0 0)

>
> (* Poetic license.)

Alan Perlis: LISP programmers know the value of everything and the
cost of nothing.

TheFlyingDutchman

unread,
Mar 4, 2011, 2:27:06 AM3/4/11
to
I'm no expert, but it looks like Common Lisp can do everything Scheme
can do, and also provides additional functionality like the powerful
Loop macro.

Edmunds Cers

unread,
Mar 4, 2011, 2:40:37 AM3/4/11
to
"WJ" <w_a_...@yahoo.com> writes:

> While dumpster-diving, I found a discarded copy of PCL.*

I'm sad to hear you have descended so low. But then, it's understandable
you have no time to work and earn money when you have to go through all
those years of threads to show us the foolishness of our ways.

> The book devotes a whole chapter to the COBOLer's delight:
> LOOP. Those who aren't comfortable with higher-order functions
> are completely dependent upon it.

Yes, it's all fun and games until the addiction kicks in. I get the
cravings any day I haven't written at least five loops. Lately, it has
been getting so bad, I stay up nights, sifting through the nice and
functional code posted in other newsgroups and rewriting it using
LOOP. So far, I have resisted the urge to post my loopified code, but I
don't know how long I will be able to stand being lonely in this
addiction.

> Using Guile Scheme, I give first the COBOL way as shown in the
> book and then the right way.

Do you also do sermons on street corners? I would so like to attend!

> The low, loopy way:
>
> (defparameter *random* (loop repeat 100 collect (random 10000)))
>
> (loop for i in *random*
> counting (evenp i) into evens
> counting (oddp i) into odds
> summing i into total
> maximizing i into max
> minimizing i into min
> finally (return (list min max total evens odds)))
>
>
> The high way:
>
> (define *random* (list-tabulate 100 (lambda _ (random 10000))))
>
> (append
> (map (rcurry apply *random*) (list min max +))
> (map (rcurry count *random*) (list even? odd?)))
>
> ==> (283 9896 503380 52 48)

Ah, yes, lispers! They have always said we knew the value of everything
and the cost of nothing. Would you be kind enough to rewrite the above
so that it would traverse the list _once_ (instead of five times) to
suite the tastes of this lowly looper? Or would you instruct me to go
rummage dumpsters for some cake, instead?

--
A change in perspective is worth 80 IQ points. --- Alan Kay

mil...@gmail.com

unread,
Mar 4, 2011, 2:46:57 AM3/4/11
to
plus some loop solutions are obviously better
insist on "functional" style in every situation is quite immature

yuridichesky

unread,
Mar 4, 2011, 2:53:52 AM3/4/11
to

I guess there must be a reason Scheme has no LOOP (TCO eliminates need
for one? Lack of GO makes it hard to implement?). What do the experts
say?

- Yuri

Edmunds Cers

unread,
Mar 4, 2011, 3:13:29 AM3/4/11
to
yuridichesky <yuridi...@gmail.com> writes:

> I guess there must be a reason Scheme has no LOOP (TCO eliminates need
> for one? Lack of GO makes it hard to implement?).

On what do you base your guess? Do plenty of programming languages have
the equivalents of LOOP? Is this a common language feature? If that
isn't the case, you should ask wether LOOP was considered for inclusion
at all, before asking for reasons why it wasn't included.

> What do the experts say?

I am by no way an expert, but I think any real iteration construct would
run contrary to Schemes philosophy on recursion as *the* generic looping
construct. The closest Scheme comes to iteration is the named let which
is actually a form of recursion too.

Marco Antoniotti

unread,
Mar 4, 2011, 3:38:21 AM3/4/11
to

Scheme has "named let" (just a macro away in CL). With that you can
have LOOP (well, the basic stuff at least) as well; mandated TCO does
the rest. Plus, Scheme has DO (as Common Lisp, which has DO and DO*)
another more basic iteration construct.

Cheers
--
Marco

P.S. WJ does not known about DO in Scheme! :)

Paul Rubin

unread,
Mar 4, 2011, 3:47:01 AM3/4/11
to
Edmunds Cers <edm...@laivas.lv> writes:
> I am by no way an expert, but I think any real iteration construct would
> run contrary to Schemes philosophy on recursion as *the* generic looping
> construct. The closest Scheme comes to iteration is the named let which
> is actually a form of recursion too.

I think that is basically right, though recursion itself can be
implemented with call/cc or with a fixpoint combinator.

In functional style, also, most loops can be replaced with calls to
higher-order functions like map and reduce (aka fold), instead of
directly using recursion.

vanekl

unread,
Mar 4, 2011, 4:14:21 AM3/4/11
to
On Friday, March 4, 2011 3:13:29 AM UTC-5, Edmunds Cers wrote:
> yuridichesky <yuridi...@gmail.com> writes:
>
> > I guess there must be a reason Scheme has no LOOP (TCO eliminates need
> > for one? Lack of GO makes it hard to implement?).
>
> On what do you base your guess?

He based his guess on two points which he listed. You should be more careful reading the post before responding, especially if it makes you emotional.

> ... Do plenty of programming languages have
> the equivalents of LOOP?

If the language is imperative or has imperative features, yes, a non-recursive looping mechanism is usually provided or there are enough constructs to build the equivalent of LOOP, perhaps not in-line, but certainly as an assembly of functions.

> ... Is this a common language feature?

Yes, for most languages it is (explanation above).

> ... If that
> isn't the case, you should ask wether [SIC] LOOP was considered for inclusion


> at all, before asking for reasons why it wasn't included.

This point you are making is not relevant on several levels:

1) non-recursive iteration is common (discussed above);
2) the question was directed toward Scheme since it is such a close dialect of CL, and not directed toward other languages, or other languages in general;
3) it was an honest question: Scheme doesn't have LOOP, and since it is so similar to CL there must be a reason why it was left out. So why?
4) the question pertains to what yuri finds conflicting, not what _you_ find of interest. Pretending that his question has no relevance is condescending.

If you want to play the NG bully, direct your misguided, self-righteous rage at me instead of yuri, but I'll probably just ignore it as I hope others will, as well.

Try putting yourself in yuri's shoes and you might gain those 80 IQ points you keep mentioning at the bottom of your posts.

Tim Bradshaw

unread,
Mar 4, 2011, 4:39:35 AM3/4/11
to
On 2011-03-04 07:53:52 +0000, yuridichesky said:

> I guess there must be a reason Scheme has no LOOP (TCO eliminates need
> for one? Lack of GO makes it hard to implement?). What do the experts
> say?

Scheme has GO, just in a form that is harder to understand than GO.

Edmunds Cers

unread,
Mar 4, 2011, 4:44:35 AM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:

> In functional style, also, most loops can be replaced with calls to
> higher-order functions like map and reduce (aka fold), instead of
> directly using recursion.

I think that iteration still offers a higher level of abstraction than
recursion, because it separates the control flow from the operations. So
the choice of idiom should run as "if cannot use higher order function,
use iteration; if cannot use iteration, use recursion". ("Cannot" being
relative, of course.)

WJ's last example wouldn't be at all pretty using a higher order
function in a way that traverses the list only once. Iteration is
clearer here, because it expresses the intent better. Moreover, in cases
like this it is just as declarative as using higher order functions. A
typical example of such a case would be

(loop as elem in list
collect (f elem) into res1
collect (g elem) into res2
finally (return (values res1 res2)))

I cannot come up with a nice equivalent using built in higher order
functions. The most straightforward way seems to be something like

(let ((res (mapcar (lambda (elem) (cons (f elem) (g elem)))
list)))
(values (mapcar 'car res) (mapcar 'cdr res)))

which would be fine in a lazy language, albeit still cryptic, but must
traverse the list three times in a strict language.

Pascal J. Bourguignon

unread,
Mar 4, 2011, 5:11:27 AM3/4/11
to
Edmunds Cers <edm...@laivas.lv> writes:

> "WJ" <w_a_...@yahoo.com> writes:
>
>> While dumpster-diving, I found a discarded copy of PCL.*
>
> I'm sad to hear you have descended so low.

I'm more worried about how a copy of PCL landed in a dump.


>> The book devotes a whole chapter to the COBOLer's delight:
>> LOOP. Those who aren't comfortable with higher-order functions
>> are completely dependent upon it.
>

> Ah, yes, lispers! They have always said we knew the value of everything
> and the cost of nothing. Would you be kind enough to rewrite the above
> so that it would traverse the list _once_ (instead of five times) to
> suite the tastes of this lowly looper? Or would you instruct me to go
> rummage dumpsters for some cake, instead?

The problem is to find a compiler that would be able to optimize out
those five walks.

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

Edmunds Cers

unread,
Mar 4, 2011, 5:21:41 AM3/4/11
to
vanekl <lou....@gmail.com> writes:

> On Friday, March 4, 2011 3:13:29 AM UTC-5, Edmunds Cers wrote:
>> yuridichesky <yuridi...@gmail.com> writes:
>>
>> > I guess there must be a reason Scheme has no LOOP (TCO eliminates need
>> > for one? Lack of GO makes it hard to implement?).
>>
>> On what do you base your guess?
>
> He based his guess on two points which he listed. You should be more
> careful reading the post before responding, especially if it makes you
> emotional.

Why on earth do you think my response was emotional? The point of my
post was to point out the epistemological fallacy Yuridichesky is making
and which you too haven't noticed. Before asking for technical reasons
why feature X is not present in a programming language, one *has* to ask
whether there are some social reasons, first. Otherwise you avoid
explanations and run straight to rationalisations.

>> ... Do plenty of programming languages have
>> the equivalents of LOOP?
>
> If the language is imperative or has imperative features, yes, a
> non-recursive looping mechanism is usually provided or there are
> enough constructs to build the equivalent of LOOP, perhaps not
> in-line, but certainly as an assembly of functions.

But the question was about CL's LOOP, not about iteration mechanisms,
like the named LET I mentioned. As was pointed out by Marco (and missed
by me), Scheme also has DO (albeit its semantics are still defined in a
way compatible to a recursive definition). The LOOP macro is a unique
feature of CL (shared with some predecessors, probably), not even that
beloved by many Common-Lispers and loathed by Schemers.

>> ... If that
>> isn't the case, you should ask wether [SIC] LOOP was considered for inclusion
>> at all, before asking for reasons why it wasn't included.
>
> This point you are making is not relevant on several levels:
>
> 1) non-recursive iteration is common (discussed above);

But the likes of LOOP are very uncommon.

> 2) the question was directed toward Scheme since it is such a close
> dialect of CL, and not directed toward other languages, or other
> languages in general;

How is Scheme a close dialect of CL? There are too many deep
philosophical divides between those two languages, to call them close
dialects of lisp. ISLisp would be a close dialect of CL, for example.

> 3) it was an honest question: Scheme doesn't have LOOP, and since it
> is so similar to CL there must be a reason why it was left out. So
> why?

And I gave my honest answer that you have deleted for some (honest?)
reason.

> 4) the question pertains to what yuri finds conflicting, not what
> _you_ find of interest. Pretending that his question has no relevance
> is condescending.

You surely must have read a different answer from the one I posted!

> If you want to play the NG bully, direct your misguided,
> self-righteous rage at me instead of yuri, but I'll probably just
> ignore it as I hope others will, as well.

It was not my intent to intimidate anyone. It is a simple fact of life
that many "technical" questions about programming languages have
"social" answers. It is my opinion that this is one of those cases.

> Try putting yourself in yuri's shoes and you might gain those 80 IQ
> points you keep mentioning at the bottom of your posts.

Who's the self-righteous and raging one here?

Pascal Costanza

unread,
Mar 4, 2011, 5:27:28 AM3/4/11
to

The goal of Scheme is (at least was until R5RS) to be a minimal language
that provides everything you need to build more full-fledged features
(such as something similar to loop) on top. LOOP-style or ITERATE-style
iteration constructs exist for Scheme in the form of libraries. I don't
know to what extent they are used in the Scheme community, but they
certainly have users.


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/

Edmunds Cers

unread,
Mar 4, 2011, 5:32:57 AM3/4/11
to
"Pascal J. Bourguignon" <p...@informatimago.com> writes:

> The problem is to find a compiler that would be able to optimize out
> those five walks.

I've been thinking some time about a construct like

(with-lazy
(append
(mapcar (rcurry apply *random*) (list min max +))
(mapcar (rcurry count *random*) (list evenp oddp))))

that would assume the applied functions to be side-effect free and roll
the whole thing into a single iteration construct. To make this really fly,
however, one should also be able to define functions in such a way that
any implicit traversals would be lazy too. So that one could do
something like

(with-lazy
(mapcar fn (explode-string str))),

for example, while having EXPLODE-STRING return a normal list outside of
WITH-LAZY.

ok

unread,
Mar 4, 2011, 5:44:27 AM3/4/11
to
On 4 Mar, 04:53, "WJ" <w_a_x_...@yahoo.com> wrote:
> LOOP.

Thanks for your perfect strategy to know all the benefits of LOOP!

I have to remember your ingenious moves:
1) post a pseudo-hating message
2) wait

Well done!

Rainer Joswig

unread,
Mar 4, 2011, 5:46:28 AM3/4/11
to

See SERIES in CLtL2...

Edmunds Cers

unread,
Mar 4, 2011, 5:56:55 AM3/4/11
to
Rainer Joswig <jos...@lisp.de> writes:

> See SERIES in CLtL2...

Yes, that is along the lines I have in mind, only integrated with
lists. Basically, this would have to be a code walker that would replace
the list operations with the appropriate series operations and would
automatically collect the lists from functions used outside WITH-LAZY.

vanekl

unread,
Mar 4, 2011, 6:18:44 AM3/4/11
to
On Mar 4, 5:21 am, Edmunds Cers <edmu...@laivas.lv> wrote:

> vanekl <lou.va...@gmail.com> writes:
> > On Friday, March 4, 2011 3:13:29 AM UTC-5, Edmunds Cers wrote:
> >> yuridichesky <yuridi...@gmail.com> writes:
>
> >> > I guess there must be a reason Scheme has no LOOP (TCO eliminates need
> >> > for one? Lack of GO makes it hard to implement?).  
>
> >> On what do you base your guess?
>
> > He based his guess on two points which he listed. You should be more
> > careful reading the post before responding, especially if it makes you
> > emotional.
>
> Why on earth do you think my response was emotional?

Perhaps you didn't intend it to be, but it comes across as such.


> The point of my
> post was to point out the epistemological fallacy Yuridichesky is making
> and which you too haven't noticed. Before asking for technical reasons
> why feature X is not present in a programming language, one *has* to ask
> whether there are some social reasons, first. Otherwise you avoid
> explanations and run straight to rationalisations.

Yeah, in your mind I'm sure this is true. Not everybody thinks the way
you do, Edmunds, nor shares your priorities. Another example of your
overwhelming self-righteousness -- you can't even entertain for more
than a moment that somebody else may have an equally valid position
and a different perspective.

Well, I hope I only have to say this once, but you are an incredibly
bright guy but if you would start giving other people the benefit of
the doubt before tearing into somebody your arguments may not be
discarded out of hand so much. You might even make a new friend. But
maybe none of this is of consequence to you.


> >> ... Do plenty of programming languages have
> >> the equivalents of LOOP?
>
> > If the language is imperative or has imperative features, yes, a
> > non-recursive looping mechanism is usually provided or there are
> > enough constructs to build the equivalent of LOOP, perhaps not
> > in-line, but certainly as an assembly of functions.
>
> But the question was about CL's LOOP, not about iteration mechanisms,

I very explicitly defined the concept of "LOOP." You know as well as I
that it's highly uncommon for languages to identically copy other
language constructs. There has to be some redefinition of LOOP for
yuri's question to make sense. To pretend that there must be an
_exact_ replication in other languages is disingenuous and perhaps
purposely misleading. But I'll give you the benefit of the doubt and
assume your thought processes are much more rigid than mine.


> like the named LET I mentioned. As was pointed out by Marco (and missed
> by me), Scheme also has DO (albeit its semantics are still defined in a
> way compatible to a recursive definition). The LOOP macro is a unique
> feature of CL (shared with some predecessors, probably), not even that
> beloved by many Common-Lispers and loathed by Schemers.

Yes, LOOP per se is unique to CL. Looping, on the other hand is not.
We are making opposite distinctions. You have obviously decided that
your interpretation is the one and only one correct interpretation,
and cannot even acknowledge that there may be others, even when faced
with evidence to the contrary. Yet another example of how you roll
over other people. Whether you intend to do this or not, it's tiring.


> >> ... If that
> >> isn't the case, you should ask wether [SIC] LOOP was considered for inclusion
> >> at all, before asking for reasons why it wasn't included.
>
> > This point you are making is not relevant on several levels:
>
> > 1) non-recursive iteration is common (discussed above);
>
> But the likes of LOOP are very uncommon.

Only if we are talking exact replications of LOOP, I'll give you that.
But I thought that was so obvious that it needn't be mentioned.


> > 2) the question was directed toward Scheme since it is such a close
> > dialect of CL, and not directed toward other languages, or other
> > languages in general;
>
> How is Scheme a close dialect of CL?

I find you hard to take seriously at times like this. Both CL and
Scheme are *both* called Lisp, share a common heritage, share similar
syntax, share common underlying data structures, share several common
design elements, and yet you feign ignorance of all this. You are
better than this.


> There are too many deep
> philosophical divides between those two languages, to call them close
> dialects of lisp. ISLisp would be a close dialect of CL, for example.
>
> > 3) it was an honest question: Scheme doesn't have LOOP, and since it
> > is so similar to CL there must be a reason why it was left out. So
> > why?
>
> And I gave my honest answer that you have deleted for some (honest?)
> reason.

Explained in my next paragraph below.


> > 4) the question pertains to what yuri finds conflicting, not what
> > _you_ find of interest. Pretending that his question has no relevance
> > is condescending.
>
> You surely must have read a different answer from the one I posted!

If you are referring to the technical answer about why you think LOOP
is not part of Scheme, yes, I saw that. My post was directed towards
your attitude, not the technical portion of your post. Since the
subject of my post was your out-of-control attitude I didn't feel
including the superfluous technical portion of your post warranted
inclusion.


> > If you want to play the NG bully, direct your misguided,
> > self-righteous rage at me instead of yuri, but I'll probably just
> > ignore it as I hope others will, as well.
>
> It was not my intent to intimidate anyone. It is a simple fact of life
> that many "technical" questions about programming languages have
> "social" answers. It is my opinion that this is one of those cases.

I'm sorry if I misinterpreted your post but your text can be
overbearing, and I'm afraid could be detrimental to those who want to
learn lisp. They may be afraid to ask a question next time.


> > Try putting yourself in yuri's shoes and you might gain those 80 IQ
> > points you keep mentioning at the bottom of your posts.
>
> Who's the self-righteous and raging one here?

!-1 > /dev/null


> --
> A change in perspective is worth 80 IQ points. --- Alan Kay

Edmunds, you always have something interesting to say, but if you
could lighten up a little I think your points would go further. Based
on this post of yours, I still don't think you understand my main
point: I'm asking you to more carefully consider the tone of your
posts.

Paul Rubin

unread,
Mar 4, 2011, 6:34:47 AM3/4/11
to
Edmunds Cers <edm...@laivas.lv> writes:
> (let ((res (mapcar (lambda (elem) (cons (f elem) (g elem)))
> list)))
> (values (mapcar 'car res) (mapcar 'cdr res)))
>
> which would be fine in a lazy language, albeit still cryptic, but must
> traverse the list three times in a strict language.

If you don't mind traversing the list twice, then

(list (map f xs) (map g xs))

where xs is your list (and "list" is the built-in function) seems to
take care of the whole thing. I'm not convinced that's really worse
than traversing once, and the compiler might even be able to fuse the
two operations, but let's see, in Haskell I'd write:

unzip . map (f &&& g) $ list

The &&& combinator is from Control.Arrow and does what your internal
lambda does. I guess in Scheme you could spell it all out:

(map reverse! (fold (lambda (e r) (list (cons (f e) (car r))
(cons (g e) (cadr r)))) x0 xs))

You build up two lists in parallel and reverse! them (ok, more
traversals). I'm guessing the CL loop/collect thing does something
similar, but maybe it does some set-cdr! awfulness to build the two
lists in place. Perhaps there's away to do something similar with
Scheme--I'm not much of a Scheme user so don't know.

Rainer Joswig

unread,
Mar 4, 2011, 6:35:43 AM3/4/11
to
On 4 Mrz., 12:18, vanekl <lou.va...@gmail.com> wrote:

> Yes, LOOP per se is unique to CL. Looping, on the other hand is not.

Not really.

There have been reimplementations/redesigns of LOOP for Scheme:


The Anatomy of a Loop, A story of scope and control, Olin Shivers
http://citeseer.ist.psu.edu/viewdoc/download;jsessionid=824ABD01D5AFB18C1FCB20465967C86F?doi=10.1.1.128.5560&rep=rep1&type=pdf

Loopy-loop
http://wiki.call-cc.org/eggref/4/loopy-loop

Yow! LOOP macros are LOOPY!
http://groups.google.com/group/comp.lang.scheme/msg/60dcac5ea812398

Common Lisp itself has a redesign of LOOP:
http://common-lisp.net/project/iterate/doc/Don_0027t-Loop-Iterate.html

vanekl

unread,
Mar 4, 2011, 6:43:39 AM3/4/11
to
On Friday, March 4, 2011 6:35:43 AM UTC-5, Rainer Joswig wrote:

I'm referring to the official version of Scheme the language. Sorry if that was not clear.

Pascal J. Bourguignon

unread,
Mar 4, 2011, 6:49:47 AM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:

> Edmunds Cers <edm...@laivas.lv> writes:
>> (let ((res (mapcar (lambda (elem) (cons (f elem) (g elem)))
>> list)))
>> (values (mapcar 'car res) (mapcar 'cdr res)))
>>
>> which would be fine in a lazy language, albeit still cryptic, but must
>> traverse the list three times in a strict language.
>
> If you don't mind traversing the list twice, then
>
> (list (map f xs) (map g xs))
>
> where xs is your list (and "list" is the built-in function) seems to
> take care of the whole thing. I'm not convinced that's really worse
> than traversing once, and the compiler might even be able to fuse the
> two operations, but let's see, in Haskell I'd write:
>
> unzip . map (f &&& g) $ list

There's no reason to write it differently in Common Lisp:


(unzip (mapcar (&&& (function f) (function g)) list))

with:

(defun &&& (funs)
(lambda (arg)
(mapcar (lambda (fun) (funcall fun arg)) funs)))

My point being that all these discussions are purposeless, you can
always abstract away all you want.

Paul Rubin

unread,
Mar 4, 2011, 7:14:09 AM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:
> (map reverse! (fold (lambda (e r) (list (cons (f e) (car r))
> (cons (g e) (cadr r)))) x0 xs))

Whooops, forgot initialization of x0, use (list '() '()) instead.

OK, here's a completely insane mutating version, that traverses just
once. Maybe there's a more idiomatic way to do it, and it could
certainly be factored out into combinators:

(define xs '("a" "b" "c"))
(define (f x) (string-append "f" x))
(define (g x) (string-append "g" x))
(define result (let ((a (list #f)) ; dummy starting lists
(b (list #f)))
(fold (lambda (e r)
(let ((fe (list (f e)))
(ge (list (g e))))
(set-cdr! (car r) fe)
(set-cdr! (cadr r) ge)
(list (cdar r) (cdadr r))))
(list a b) xs)
(list (cdr a) (cdr b))))

In the old days they said reverse!/nreverse was better than this type of
crock anyway, but maybe traversals are worse for cache performance now.

Paul Rubin

unread,
Mar 4, 2011, 7:15:55 AM3/4/11
to
"Pascal J. Bourguignon" <p...@informatimago.com> writes:
> There's no reason to write it differently in Common Lisp:
> (unzip (mapcar (&&& (function f) (function g)) list))

But that traverses the list multiple times, because of CL's strict
evaluation. The point of the Haskell example was getting lazy
evaluation with no effort.

Edmunds Cers

unread,
Mar 4, 2011, 7:26:27 AM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:

> Edmunds Cers <edm...@laivas.lv> writes:
>> (let ((res (mapcar (lambda (elem) (cons (f elem) (g elem)))
>> list)))
>> (values (mapcar 'car res) (mapcar 'cdr res)))
>>
>> which would be fine in a lazy language, albeit still cryptic, but must
>> traverse the list three times in a strict language.
>
> If you don't mind traversing the list twice, then
>
> (list (map f xs) (map g xs))

This just goes to show how you (me in this case) can get trapped in a
single mindset. For an strict language your solution should be the
obvious choice. ;-)

> I'm guessing the CL loop/collect thing does something similar, but
> maybe it does some set-cdr! awfulness to build the two lists in place.

It does the awfulness and achieves single traversal of the list this
way. If you don't mind multiple traversals of the lists (nor should you
in most cases), then my point is moot. It's just that WJ keeps bashing
LOOP while offering up clearly less efficient solutions.

Pascal J. Bourguignon

unread,
Mar 4, 2011, 7:45:34 AM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:

(shadow 'mapcar)
(import 'cl-lazy:mapcar)

I don't care whether the effort invested in implementing lazyness is
spent by the compiler writer or the library writer. (But agreed, CL is
not helpful there).

Tim Bradshaw

unread,
Mar 4, 2011, 8:12:55 AM3/4/11
to
On 2011-03-04 12:26:27 +0000, Edmunds Cers said:

>
>> I'm guessing the CL loop/collect thing does something similar, but
>> maybe it does some set-cdr! awfulness to build the two lists in place.
>
> It does the awfulness and achieves single traversal of the list this
> way.

Worth mentioning, perhaps, that it's quite easy to write macrology
which does the awfulness for you without needing to use LOOP. This is
quite nice if your list collection pattern is irregular (for instance
you might be recursing over some large structure occasionally
collecting an item).

Edmunds Cers

unread,
Mar 4, 2011, 8:20:08 AM3/4/11
to
vanekl <lou....@gmail.com> writes:

> On Mar 4, 5:21 am, Edmunds Cers <edmu...@laivas.lv> wrote:
>> vanekl <lou.va...@gmail.com> writes:

>> But the question was about CL's LOOP, not about iteration mechanisms,
>
> I very explicitly defined the concept of "LOOP." You know as well as I
> that it's highly uncommon for languages to identically copy other
> language constructs. There has to be some redefinition of LOOP for
> yuri's question to make sense.

Well, *you* did. But Yuri posted his question in response to this post
from The Flying Dutchman:

I'm no expert, but it looks like Common Lisp can do everything Scheme
can do, and also provides additional functionality like the powerful
Loop macro.

And his question absolutely makes sense even (and especially) if we
assume he meant CL's LOOP, since it was implied that CL's LOOP is a
powerful feature.

> To pretend that there must be an _exact_ replication in other
> languages is disingenuous and perhaps purposely misleading.

No one is talking about an _exact_ replication. I asked for "equivalent"
features using the coloquial sense of the word. Why don't you give *me*
the benefit of the doubt?

> Yes, LOOP per se is unique to CL. Looping, on the other hand is not.
> We are making opposite distinctions. You have obviously decided that
> your interpretation is the one and only one correct interpretation,
> and cannot even acknowledge that there may be others, even when faced
> with evidence to the contrary. Yet another example of how you roll
> over other people. Whether you intend to do this or not, it's tiring.

So, then my post could be fixed by prepending the sentence "I assume you
are talking about the LOOP macro as it is in CL" ? Wasn't this
assumption evident from the answer? If Yuri's intended meaning was along
the lines of your interpretation, then that question was answered by
Marco. Note, he didn't prepend "I assume you talk about iteration in
general," either.

>> But the likes of LOOP are very uncommon.
>
> Only if we are talking exact replications of LOOP, I'll give you that.
> But I thought that was so obvious that it needn't be mentioned.

Then you are the one making assumptions. Why would you assume anyone
would think there are *no* iteration constructs in Scheme, when they are
ubiquitous in any other programming language?

>> How is Scheme a close dialect of CL?
>
> I find you hard to take seriously at times like this. Both CL and
> Scheme are *both* called Lisp, share a common heritage, share similar
> syntax, share common underlying data structures, share several common
> design elements, and yet you feign ignorance of all this.

Why do you insist on doing all the things you accuse me of doing? I am
aware and _assuming_ that Scheme is a lisp dialect. In what other way
could you have meant _dialect_? Dialects of programming languages? As
far Lisp dialects go, Scheme and CL are currently almost opposites to
the extent that other dialects are characterized by listing features
they share with the one or the other.

> My post was directed towards your attitude, not the technical portion
> of your post. Since the subject of my post was your out-of-control
> attitude I didn't feel including the superfluous technical portion of
> your post warranted inclusion.

I cannot do anything but to implore you to understand that there was
neither malice nor arrogance in my attitude. I think you will see this,
if you reread my original post in light of the explanations given here.

I guess the only thing that can be construed in the way you do, is the
initial question "on what do you base your guess?", which, of course,
_was_ rhetorical. But this had everything to do with how I wanted to
structure my answer, given what I wanted to convey, and nothing with my
attitude. In retrospect, I could had structured the answer differently,
starting with "You could be making a common assumption that language
features are included or excluded based only on their technical
merits...," but I just didn't realize that this was such a big deal.

> Edmunds, you always have something interesting to say, but if you
> could lighten up a little I think your points would go further. Based
> on this post of yours, I still don't think you understand my main
> point: I'm asking you to more carefully consider the tone of your
> posts.

Ok, I get your point and perhaps you are right (while for written text
tone is still largely in the head of the reader). I will try to take
more time considering how my posts come across. Starting next post. ;-)

Barry Fishman

unread,
Mar 4, 2011, 10:32:07 AM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:

Although Haskell does the evaluation lazily. doesn't it still
traverse the list multiple time? Rather than all at once it does it
as consumed with increased memory thrashing. Not a help if you are
using all of the resultant list anyway.

--
Barry Fishman

Barry Fishman

unread,
Mar 4, 2011, 10:41:57 AM3/4/11
to
"Pascal J. Bourguignon" <p...@informatimago.com> writes:

> Edmunds Cers <edm...@laivas.lv> writes:
>
>> "WJ" <w_a_...@yahoo.com> writes:
>>
>>> While dumpster-diving, I found a discarded copy of PCL.*
>>
>> I'm sad to hear you have descended so low.
>
> I'm more worried about how a copy of PCL landed in a dump.

I accidentally left my copy at a hospital that I was visiting, and
somebody picked it up and did not return it to lost and found.

Maybe it was put in the trash by a Lisp hating janitor.

--
Barry Fishman

gary.schiltz

unread,
Mar 4, 2011, 11:03:42 AM3/4/11
to
On Mar 3, 10:53 pm, "WJ" <w_a_x_...@yahoo.com> wrote:
> While dumpster-diving, I found a discarded copy of PCL.*

Cool! If it's in good condition, sell it on ebay. Quality books like
that tend to keep their value quite nicely!

Don Geddis

unread,
Mar 4, 2011, 10:50:06 AM3/4/11
to
Tim Bradshaw <t...@tfeb.org> wrote on Fri, 4 Mar 2011 :
> Worth mentioning, perhaps, that it's quite easy to write macrology
> which does the awfulness for you without needing to use LOOP.

Isn't that exactly what LOOP is? A macro which hides the efficient
implementation details of traversing and collecting lists.

How does it help to write _another_ (non-standard!) macro, to accomplish
the same thing? Why is the goal to avoid LOOP?

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org
Sometimes I lie awake at night, and I ask, "Where have I gone wrong?"
Then a voice says to me, "This is going to take more than one night."
-- Charlie Brown, _Peanuts_ [Charles Schulz]

Edmunds Cers

unread,
Mar 4, 2011, 11:34:30 AM3/4/11
to
Barry Fishman <barry_...@acm.org> writes:

> Paul Rubin <no.e...@nospam.invalid> writes:
>
>> Pascal J. Bourguignon" <p...@informatimago.com> writes:
>>> There's no reason to write it differently in Common Lisp:
>>> (unzip (mapcar (&&& (function f) (function g)) list))
>>
>> But that traverses the list multiple times, because of CL's strict
>> evaluation. The point of the Haskell example was getting lazy
>> evaluation with no effort.
>
> Although Haskell does the evaluation lazily. doesn't it still
> traverse the list multiple time? Rather than all at once it does it
> as consumed with increased memory thrashing.

Within a lazy evaluation model this would return a list of two promises
- actually functions that calculate the next element only when
required. Thus a FIRST on the first uncalculated element of the returned
sequences would be roughly equivalent to

(car (let ((top (pop list)))
(cons (apply f top)
(apply g top))))

To make this viable, you cache the already calculated results for later
reuse (or for use by referring the other sequence).

> Not a help if you are using all of the resultant list anyway.

If using the whole list, you can imagine the lazy function being
equivalent to iteration over the list while applying the functions to
every element and accumulating the results in lists. While in a strict
version a new list is constructed by MAPCAR first, and then from that
list a new list of two lists is constructed by the UNZIP.

Tim Bradshaw

unread,
Mar 4, 2011, 11:48:03 AM3/4/11
to
On 2011-03-04 15:50:06 +0000, Don Geddis said:

> Isn't that exactly what LOOP is? A macro which hides the efficient
> implementation details of traversing and collecting lists.
>
> How does it help to write _another_ (non-standard!) macro, to accomplish
> the same thing? Why is the goal to avoid LOOP?

I think you've not understood what I meant, probably because I didn't
express myself very well: I use LOOP pervasively, but there are times
when you want to collect lists forwards which aren't just loops. A
typical pattern of use of a collecting macro might be something like
this:

(collecting
(huge-search-function structure #'(lambda (x) (collect x))))

Where HUGE-SEARCH-FUNCTION walks some structure in some recursive way.
(You have to wrap COLLECT in a function like this because in my
implementation it's a local macro: it probably should not be, but it's
very old code and I'm loath to change it now).

Even further removed is this thing:

(defun make-collector ()
;; returns a cons whose car is the collector function, and whose cdr
;; is the list it collects into.
(collecting
(collect #'(lambda (e)
(collect e)))))


Nicolas Neuss

unread,
Mar 4, 2011, 12:30:05 PM3/4/11
to
Tim Bradshaw <t...@tfeb.org> writes:

> On 2011-03-04 15:50:06 +0000, Don Geddis said:
>
>> Isn't that exactly what LOOP is? A macro which hides the efficient
>> implementation details of traversing and collecting lists.
>>
>> How does it help to write _another_ (non-standard!) macro, to accomplish
>> the same thing? Why is the goal to avoid LOOP?
>
> I think you've not understood what I meant, probably because I didn't
> express myself very well: I use LOOP pervasively, but there are times when
> you want to collect lists forwards which aren't just loops. A typical
> pattern of use of a collecting macro might be something like this:
>
> (collecting
> (huge-search-function structure #'(lambda (x) (collect x))))

I sometimes use the following:

(defun mapper-collect (mapper &rest rest-args)
"Collects the arguments with which a mapping construct calls a given
function. E.g.
@lisp
(mapper-collect #'mapc '(3 4 5)) @result{} (3 4 5)
@end lisp"
(let ((result ()))
(apply mapper (_ (push _ result)) rest-args)
(nreverse result)))

[To avoid reversing the list is left as an exercise.]

With this your example would turn into

(mapper-collect #'huge-search-function structure)

Analogously, I have also mapper-sum, mapper-some, mapper-count, etc.

Nicolas

Paul Rubin

unread,
Mar 4, 2011, 3:43:09 PM3/4/11
to
"Pascal J. Bourguignon" <p...@informatimago.com> writes:
> (shadow 'mapcar)
> (import 'cl-lazy:mapcar)

Oh that is cool, I'll have to read about it. Thanks.

Pascal J. Bourguignon

unread,
Mar 4, 2011, 4:00:00 PM3/4/11
to
Paul Rubin <no.e...@nospam.invalid> writes:

There's an actual clazy library, but I don't know if it includes a
mapcar.

I'm partisant of the wishfull programming methodology.

Marco Antoniotti

unread,
Mar 5, 2011, 3:53:37 AM3/5/11
to
On Mar 4, 11:32 am, Edmunds Cers <edmu...@laivas.lv> wrote:
> "Pascal J. Bourguignon" <p...@informatimago.com> writes:
>
> > The problem is to find a compiler that would be able to optimize out
> > those five walks.
>
> I've been thinking some time about a construct like
>
> (with-lazy
>     (append
>      (mapcar (rcurry apply *random*) (list min max +))
>      (mapcar (rcurry count *random*) (list evenp oddp))))

... and here you have it :)

(lazy:lazily


(mapcar (rcurry apply *random*) (list min max +))
 (mapcar (rcurry count *random*) (list evenp oddp))))

This classic *and* substantiated shameless plug :) points you to CLAZY
http://common-lisp.net/projects/clazy

Come join the fun.

Cheers
--
MA

Marco Antoniotti

unread,
Mar 5, 2011, 3:54:52 AM3/5/11
to

... and read about it here ...

http://common-lisp.net/projects/clazy

Cheers
--
MA

Marco Antoniotti

unread,
Mar 5, 2011, 4:23:49 AM3/5/11
to

Yep. What this boils down to is - I believe - that sometimes you want
to "save the state" of a "traversal". Also, that sometimes, the
(temporal) order in which you traverse does not need to be the
structural order of the "items". But then I have been reading GLS on
"foldr considered slightly harmful"...

Cheers
--
Marco

Edmunds Cers

unread,
Mar 7, 2011, 2:53:21 PM3/7/11
to
Marco Antoniotti <mar...@gmail.com> writes:

> On Mar 4, 11:32 am, Edmunds Cers <edmu...@laivas.lv> wrote:
>
>> I've been thinking some time about a construct like
>>
>> (with-lazy
>>     (append
>>      (mapcar (rcurry apply *random*) (list min max +))
>>      (mapcar (rcurry count *random*) (list evenp oddp))))
>
> ... and here you have it :)
>
> (lazy:lazily
> (mapcar (rcurry apply *random*) (list min max +))
>  (mapcar (rcurry count *random*) (list evenp oddp))))

This does almost what I had in mind - except forcing the value on exit,
so that all "laziness" would be contained inside LAZILY. To get to the
wanted semantics for the simplest case i can do (using LAZY)

(defun force-all (lazy-list)
(loop as top = lazy-list then (tail top)
while top
collect (head top)))

(defmacro with-lazy (&body body)
`(force-all (lazily ,@body)))

to this add

(def-lazy-function mapcar (fn list)
(when list
(%cons-lazy-cons (delay (call fn (head list)))
(delay (call 'mapcar fn (tail list))))))

and it seems to do what I want for the simplest case

(with-lazy
(mapcar f (mapcar g list)))

However, the overhead of the delay-force laziness is very large. In
effect this works much slower than just doing

(mapcar f (mapcar g list))

double traversal or not.

I guess what I want to say is that the approach taken by Clazy looks
great if you need the semantics of laziness, but I don't think it is
really suited if you want laziness as an optimization strategy. Or am I
just missing something?

> This classic *and* substantiated shameless plug :) points you to CLAZY
> http://common-lisp.net/projects/clazy

Plug greatly appreciated. Ample food for thought.

WJ

unread,
May 5, 2011, 4:05:43 AM5/5/11
to
WJ wrote:

>
> The low, loopy way:
>
> (loop for (item . rest) on list
> do (format t "~a" item)
> when rest do (format t ", "))
>
>
> The high way:
>
> guile> (string-join (map object->string (iota 9)) ", ")
> "0, 1, 2, 3, 4, 5, 6, 7, 8"

Arc:

arc> (string (intersperse ", " (range 0 8)))
"0, 1, 2, 3, 4, 5, 6, 7, 8"

WJ

unread,
May 15, 2011, 5:08:34 PM5/15/11
to
WJ wrote:

>
> The low, loopy way:
>
> (loop for (item . rest) on list
> do (format t "~a" item)
> when rest do (format t ", "))
>
>
> The high way:
>
> guile> (string-join (map object->string (iota 9)) ", ")
> "0, 1, 2, 3, 4, 5, 6, 7, 8"

Arc:

Jarc> (string (intersperse ", " (range 0 8)))

WJ

unread,
May 15, 2011, 5:40:36 PM5/15/11
to
WJ wrote:

>
> The low, loopy way:
>
> (defparameter random (loop repeat 100 collect (random 10000)))
>
> (loop for i in random
> counting (evenp i) into evens
> counting (oddp i) into odds
> summing i into total
> maximizing i into max
> minimizing i into min
> finally (return (list min max total evens odds)))
>
>
> The high way:
>
> (define random (list-tabulate 100 (lambda _ (random 10000))))
>
> (append
> (map (rcurry apply random) (list min max +))
> (map (rcurry count random) (list even? odd?)))
>
> ==> (283 9896 503380 52 48)

Arc:

(= randoms (n-of 100 (rand 10000)))

(append
(map [reduce _ randoms] '(min max +))
(map [count _ randoms] (list even odd)))

==> (46 9858 481171 55 45)

Mark Tarver

unread,
May 15, 2011, 8:23:42 PM5/15/11
to

Looking back over all the examples you've provided, I actually
consider that your solutions *are* more elegant than the CL ones that
are being offered. I actually agree that what I have seen being
written here using LOOP in CL is ugly and prolix. I wouldn't
recommend these CL solutions to any novice.

I'm wondering why this ugly construction is proving so popular in this
group, and is being used in problems which really don't merit it.
Perhaps there is a group mind forming here - people trying to program
in a uniquely 'Lispy' way by using a feature which very few languages
support.

Indeed, LOOP in all its gory detail is very specific to Common Lisp.

But there is a reason why LOOP was not lifted by other modern FPLs -
and its not because it is too profound. It is because nobody wanted
it.

Lisp programming here appears to be regressing to a pre-SICP style.
It's weird to see code that looks like it was written in 1970. There
is a kind of intellectual senescence happening. It's not just that
ideas about FPLs > 1985 are not being assimilated or reflected in CL.
Even the old lessons are being forgotten in a strange kind of
insularity.

I doubt though whether you will gain many converts to your cause.

Only thing I'd query is why you prefer Arc over CL, because there is,
IMO, not a lot of difference between Arc and the CL functional subset
- perhaps a few different primitives and a slightly different syntax.

Mark

Don Geddis

unread,
May 15, 2011, 10:55:53 PM5/15/11
to
Mark Tarver <dr.mt...@ukonline.co.uk> wrote on Sun, 15 May 2011:
> I actually consider that your solutions *are* more elegant than the CL
> ones that are being offered.

I agree too, that some of the arc terminology and built-in functions
seem both clear and concise. It's nice to design a new language without
the baggage of any backward compatibility.

> Indeed, LOOP in all its gory detail is very specific to Common Lisp.
> But there is a reason why LOOP was not lifted by other modern FPLs -
> and its not because it is too profound. It is because nobody wanted
> it.

But Common Lisp is not restricted to the FPL paradigm. And FPL is not
the only, or even the best, method of programming in all situations.

It may be true that nobody designing a modern _functional_ language was
interested in LOOP. But that's a long, long way from saying that LOOP
was a bad design within Common Lisp, or for that matter for other
non-FPL languages.

> Lisp programming here appears to be regressing to a pre-SICP style.

On the contrary. FPL-only is a restricted world-view, quite unlike the
deliberate diversity of programming styles that Common Lisp supports.

-- Don
_______________________________________________________________________________
Don Geddis http://don.geddis.org/ d...@geddis.org

Of all the tall tales, I think my favorite is the one about Eli Whitney and the
interchangeable parts. -- Deep Thoughts by Jack Handey [SNL]

Raffael Cavallaro

unread,
May 15, 2011, 11:42:21 PM5/15/11
to
On 2011-05-15 20:23:42 -0400, Mark Tarver said:

> But there is a reason why LOOP was not lifted by other modern FPLs -
> and its not because it is too profound. It is because nobody wanted
> it.

Nobody in the FPL community wanted LOOP because LOOP is a DSL for
iteration, something which seems perfectly natural to lispers, people
who see their programming language as a tool for building DSLs, but
seems inelegant or irrelevant to those who see their language as a as a
theorem proving aid or a platform for studying applied type theory.

To turn your assertion around, modern FPLs seem to many lispers to have
been intentionally crippled as tools for building DSLs (i.e., they lack
easy macro programming).

As to *why* this is the case, I think this is as good an answer as any:

<http://www.loper-os.org/?p=401>

In brief, modern FPLs are *already* targeted at their intended problem
domains - theorem proving and type theory. In the academic context in
which they developed, DSLs and macro programming seemed irrelevant.

Lisp is a language for targeting as yet unknown problems though the
building of domain specific languages. Lisp macros get you useful DSLs
more easily than FPLs do.

Lastly, I do not think that there is some sort of necessary progression
of quality from languages that freely allow mutation to FPLs of the *ml
or haskel variety. Making a kind of fetish of referential transparency
imho yields a language that deals well with space (i.e., lexical scope)
but poorly with time (i.e., dynamic scope and mutation).

Like it or not, our cognitive apparatus has evolved over millions of
years to be rather adept at reasoning about the mutation of state
though time. As a consequence, the language in use in many problem
domains is rife with the mutation of state. It is most useful to be
able to layer syntactic abstraction over both functional abstraction
*and* mutation thus moving the programming language toward the language
already used in the problem domain. It is imho a mistake to try to
force the solution to every problem domain into the procrustean bed of
pure functional abstraction and type theory.

warmest regards,

Ralph

--
Raffael Cavallaro

Message has been deleted

TheFlyingDutchman

unread,
May 16, 2011, 10:59:33 AM5/16/11
to

>
> Looking back over all the examples you've provided, I actually
> consider that your solutions *are* more elegant than the CL ones that
> are being offered.  I actually agree that what I have seen being
> written here using LOOP in CL is ugly and prolix.  I wouldn't
> recommend these CL solutions to any novice.

Does the novice want to see solutions that are as easy to to
understand as possible or that are as clever as possible? My guess is
the former. To me that would normally mean the code has explicit,
rather than implicit loops, and is prolix rather than terse. It would
also mean that the code is unclever, posing no riddle for the novice
to solve.

There also is the question of which code is easier to change as new
requirements come in making the program more complex. For instance
when the user makes these changes: "on the third tuesday during lunch
pie will be 25% off and every Monday before 9:00am coffee will be free
and on Saturday's after 5:00pm a pint of beer is free with any fish
entree", is prolix code easier to change or code that uses the fewest
lines with functions that have implicit loops and such?

Marco Antoniotti

unread,
May 17, 2011, 4:13:24 AM5/17/11
to
On Monday, May 16, 2011 2:23:42 AM UTC+2, Mark Tarver wrote:

> On May 15, 10:08 pm, "WJ" <w_a_...@yahoo.com> wrote:
> > WJ wrote:
> >
> > > The low, loopy way:
> >
> > > (loop for (item . rest) on list
> > >     do (format t "~a" item)
> > >     when rest do (format t ", "))
> >
> > > The high way:
> >
> > > guile> (string-join (map object->string (iota 9)) ", ")
> > > "0, 1, 2, 3, 4, 5, 6, 7, 8"
> >
> > Arc:
> >
> > Jarc> (string (intersperse ", " (range 0 8)))
> > "0, 1, 2, 3, 4, 5, 6, 7, 8"
>
> Looking back over all the examples you've provided, I actually
> consider that your solutions *are* more elegant than the CL ones that
> are being offered. I actually agree that what I have seen being
> written here using LOOP in CL is ugly and prolix. I wouldn't
> recommend these CL solutions to any novice.

Well. Yes. The "functional" solutions are more "elegant". Also, since neither CL, nor Arc or guile are lazy languages, they also tend to use more memory. The novice should be warned about this side effect as well.


>
> I'm wondering why this ugly construction is proving so popular in this
> group, and is being used in problems which really don't merit it.
> Perhaps there is a group mind forming here - people trying to program
> in a uniquely 'Lispy' way by using a feature which very few languages
> support.
>
> Indeed, LOOP in all its gory detail is very specific to Common Lisp.

I don't think so. Programming in Java with Collections has a similar feel. LOOP is quite unlispy in every respect.

>
> But there is a reason why LOOP was not lifted by other modern FPLs -
> and its not because it is too profound. It is because nobody wanted
> it.
>

But then people write pages of Calmp4 to reintroduce FOR...

> Lisp programming here appears to be regressing to a pre-SICP style.
> It's weird to see code that looks like it was written in 1970. There
> is a kind of intellectual senescence happening. It's not just that
> ideas about FPLs > 1985 are not being assimilated or reflected in CL.
> Even the old lessons are being forgotten in a strange kind of
> insularity.

I don't think this is the case. I personally mix and match styles. Sometimes without really thinking whether a functional style is better or a more "imperative" one is. AFAIAC I tend to default to "what is there". It is somewhat unfortunate that the CL "library" does not have all the "names" that have piled up in the - say - Haskell library (to name a favorite of mine): take, keep, zip, tuples etc etc. So, instead of writing KEEP, I just write REMOVE-IF-NOT etc. Of course I could define KEEP, but why?

>
> I doubt though whether you will gain many converts to your cause.
>

The cause of SLDJ-loving :)


> Only thing I'd query is why you prefer Arc over CL, because there is,
> IMO, not a lot of difference between Arc and the CL functional subset
> - perhaps a few different primitives and a slightly different syntax.
>

You are asking the resident SLDJ-lover to get his/her/its mind to wrap around more complex concepts that simple one-liners :) It is a hard goal to achieve. :)

Cheers
--
MA

Pascal Costanza

unread,
May 17, 2011, 2:40:45 PM5/17/11
to
On 16/05/2011 02:23, Mark Tarver wrote:
> On May 15, 10:08 pm, "WJ"<w_a_x_...@yahoo.com> wrote:
>> WJ wrote:
>>
>>> The low, loopy way:
>>
>>> (loop for (item . rest) on list
>>> do (format t "~a" item)
>>> when rest do (format t ", "))
>>
>>> The high way:
>>
>>> guile> (string-join (map object->string (iota 9)) ", ")
>>> "0, 1, 2, 3, 4, 5, 6, 7, 8"
>>
>> Arc:
>>
>> Jarc> (string (intersperse ", " (range 0 8)))
>> "0, 1, 2, 3, 4, 5, 6, 7, 8"
>
> Looking back over all the examples you've provided, I actually
> consider that your solutions *are* more elegant than the CL ones that
> are being offered. I actually agree that what I have seen being
> written here using LOOP in CL is ugly and prolix. I wouldn't
> recommend these CL solutions to any novice.
>
> I'm wondering why this ugly construction is proving so popular in this
> group, and is being used in problems which really don't merit it.

LOOP is only ugly as long as you think it is. I'm a big LOOP fan, and
it's not ugly at all.

There are several reasons why I like it:

(a) LOOPs typically directly say what they are doing. I want to iterate
over the list and at the same time increment an integer variable. I
don't want to define a damn recursive function that does the two things
at the same time, because nothing in the code then tells me that that is
what is happening. LOOP is as clear as day in this regard. Remember:
Code should not primarily be easy to write, but easy to read!

(b) LOOP can be considerably more efficient. If I nest several mapcars
and reduce the overall result, I will create a lot of intermediate
lists, which are just unnecessary food for the garbage collector. With
LOOP, I can just fuse the steps without having to rely on some
sufficiently smart compiler (which is maybe not smart enough after all).

(c) It's easier to change things around. I can switch between lists and
arrays, switch between counting upwards or downwards, append results
instead of collecting them, collect several results in parallel, etc.,
etc. Most of these changes require only a few minor changes of the
respective LOOP keywords, and not the substantially more involved
rearranging of nested function definitions and lambda parameter lists.

A major mistake is to think of LOOP as a imperative iteration construct
(as in "ah, they are using evil side effects here"). It's better to
think of LOOP as a poor man's declarative list comprehension facility,
with the added benefit, though, that you break the abstraction barrier
and do "nasty" things in case you need them. (And, at the end of the
day, what really matters is that you get your code out the door, not
that you abide to some made up aesthetic "principle" that doesn't mean
anything by itself in a vacuum.)

For more arguments against "functional" approaches and for LOOP-style
approaches, see
http://video.google.com/videoplay?docid=-3704713569771882785# (the
interesting part starts at 4:40).


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/
The views expressed are my own, and not those of my employer.

TheFlyingDutchman

unread,
May 24, 2011, 7:19:45 PM5/24/11
to
On May 15, 5:23 pm, Mark Tarver <dr.mtar...@ukonline.co.uk> wrote:
> Looking back over all the examples you've provided, I actually
> consider that your solutions *are* more elegant than the CL ones that
> are being offered. I actually agree that what I have seen being
> written here using LOOP in CL is ugly and prolix. I wouldn't
> recommend these CL solutions to any novice.
>
> I'm wondering why this ugly construction is proving so popular in this
> group, and is being used in problems which really don't merit it.
> Perhaps there is a group mind forming here - people trying to program
> in a uniquely 'Lispy' way by using a feature which very few languages
> support.
>
> Indeed, LOOP in all its gory detail is very specific to Common Lisp.
>
> But there is a reason why LOOP was not lifted by other modern FPLs -
> and its not because it is too profound. It is because nobody wanted
> it.

I am not sure if the criticism is specific to the LOOP macro or with
regards to loop constructs in general. Assuming the later, I know
recursion, with limitations, can substitute for a loop. You also could
use the loop already built into general purpose functions like map.
What would be a summary of how to program without loop constructs?

>
> Lisp programming here appears to be regressing to a pre-SICP style.
> It's weird to see code that looks like it was written in 1970. There
> is a kind of intellectual senescence happening. It's not just that
> ideas about FPLs > 1985 are not being assimilated or reflected in CL.
> Even the old lessons are being forgotten in a strange kind of
> insularity.

It may be that the Newsgroup is now composed of many people who are
not primarily Common Lisp programmers and who have a programming style
that is more reflective of the other languages they use. I know I was
amazed to see how much talk you get with respect to a small amount of
C code.

>
> I doubt though whether you will gain many converts to your cause.
>
> Only thing I'd query is why you prefer Arc over CL, because there is,
> IMO, not a lot of difference between Arc and the CL functional subset
> - perhaps a few different primitives and a slightly different syntax.

In my observation, he has never posted code in Common Lisp, only Ruby
for a long time, then Clojure, then Scheme and now Arc. He uses terms
like Commode Lisp and Cobol Lisp. I don't know if it is accurate
describe his cause as trying to persuade people to adopt a particular
programming style.

Marco Antoniotti

unread,
May 25, 2011, 1:00:11 AM5/25/11
to
On Wednesday, May 25, 2011 1:19:45 AM UTC+2, TheFlyingDutchman wrote:

> On May 15, 5:23 pm, Mark Tarver <dr.mt...@ukonline.co.uk> wrote:
> > Looking back over all the examples you've provided, I actually
> > consider that your solutions *are* more elegant than the CL ones that
> > are being offered. I actually agree that what I have seen being
> > written here using LOOP in CL is ugly and prolix. I wouldn't
> > recommend these CL solutions to any novice.
> >
> > I'm wondering why this ugly construction is proving so popular in this
> > group, and is being used in problems which really don't merit it.
> > Perhaps there is a group mind forming here - people trying to program
> > in a uniquely 'Lispy' way by using a feature which very few languages
> > support.
> >
> > Indeed, LOOP in all its gory detail is very specific to Common Lisp.
> >
> > But there is a reason why LOOP was not lifted by other modern FPLs -
> > and its not because it is too profound. It is because nobody wanted
> > it.
>
> I am not sure if the criticism is specific to the LOOP macro or with
> regards to loop constructs in general. Assuming the later, I know
> recursion, with limitations, can substitute for a loop. You also could
> use the loop already built into general purpose functions like map.

Nope. Recursion can substitute every loop. It is the other way around that does not work (unless you have laying around an explicit or dissimulated stack that you update manually).


> What would be a summary of how to program without loop constructs?
>

Mapping and reducing, possibly with more dynamic memory being allocated.


> >
> > Lisp programming here appears to be regressing to a pre-SICP style.
> > It's weird to see code that looks like it was written in 1970. There
> > is a kind of intellectual senescence happening. It's not just that
> > ideas about FPLs > 1985 are not being assimilated or reflected in CL.
> > Even the old lessons are being forgotten in a strange kind of
> > insularity.
>
> It may be that the Newsgroup is now composed of many people who are
> not primarily Common Lisp programmers and who have a programming style
> that is more reflective of the other languages they use. I know I was
> amazed to see how much talk you get with respect to a small amount of
> C code.
>
> >
> > I doubt though whether you will gain many converts to your cause.
> >
> > Only thing I'd query is why you prefer Arc over CL, because there is,
> > IMO, not a lot of difference between Arc and the CL functional subset
> > - perhaps a few different primitives and a slightly different syntax.
>
> In my observation, he has never posted code in Common Lisp, only Ruby
> for a long time, then Clojure, then Scheme and now Arc. He uses terms
> like Commode Lisp and Cobol Lisp. I don't know if it is accurate
> describe his cause as trying to persuade people to adopt a particular
> programming style.

Well. S/he sure started as a SLDJ-lover and is slowly, slowly seeing the light. CL is a benevolent Borg. When he will post CL programs to persuade people to write in a functional way (easy enough) s/he will be more convincing :)

Cheers
--
MA


TheFlyingDutchman

unread,
May 25, 2011, 1:46:29 AM5/25/11
to
On May 24, 10:00 pm, Marco Antoniotti <marc...@gmail.com> wrote:
> > I am not sure if the criticism is specific to the LOOP macro or with
> > regards to loop constructs in general. Assuming the later, I know
> > recursion, with limitations, can substitute for a loop. You also could
> > use the loop already built into general purpose functions like map.
>
> Nope.  Recursion can substitute every loop.  It is the other way around that does not work
> (unless you have laying around an explicit or dissimulated stack that you update manually).

I thought you get a stack overflow (or some such term) if you recurse
too many times?

Marco Antoniotti

unread,
May 25, 2011, 7:50:22 AM5/25/11
to
On Wednesday, May 25, 2011 7:46:29 AM UTC+2, TheFlyingDutchman wrote:

Well, at least you stop :) Infinite loops are boring :)

Cheers
--
MA

Raffael Cavallaro

unread,
May 25, 2011, 10:07:26 AM5/25/11
to
On 2011-05-25 01:46:29 -0400, TheFlyingDutchman said:

> I thought you get a stack overflow (or some such term) if you recurse
> too many times?

Tail Calls:
<http://en.wikipedia.org/wiki/Tail_call>

In common lisp, where tail call optimization is not required by the
standard, you need to ensure that your tail call meets the requirements
for TCO in your particular implementaion to get it if it's available.

For example in CCL, you get TCO if debug optimization is < 2:
<http://trac.clozure.com/ccl/wiki/DeclareOptimize>

In Lispworks:

"In 64-bit LispWorks and on x86 platforms the compiler optimizes tail
calls unless

The compiler optimize quality debug is 3, or

There is something with dynamic scope on the stack, such as a special
binding, a catch or dynamic-extent allocation (so it is not really a
tail call)

On all other platforms the compiler optimizes tail calls unless 1.) or
2.) above apply, or

The call has more than 4 arguments and this is more than the number of
fixed (not &optional / &rest / &key ) parameters in the calling
function.

The call has more than 4 arguments and the calling function has &rest /
&key parameters."

WJ

unread,
May 27, 2011, 6:46:56 AM5/27/11
to
WJ wrote:

>
> The low, loopy way:
>
> (loop for (item . rest) on list
> do (format t "~a" item)
> when rest do (format t ", "))
>
>
> The high way:
>
> guile> (string-join (map object->string (iota 9)) ", ")
> "0, 1, 2, 3, 4, 5, 6, 7, 8"

MatzLisp (Ruby):

(0..8).to_a.join ", "
==>"0, 1, 2, 3, 4, 5, 6, 7, 8"


Mark Tarver

unread,
May 31, 2011, 7:57:05 AM5/31/11
to
> To turn your assertion around, modern FPLs seem to many lispers to have
> been intentionally crippled as tools for building DSLs (i.e., they lack
> easy macro programming).

In ML and Haskell yes. OK; to tackle the toy problem posed in a thread
here

QUOTE
A friend passed on an article regarding the difficulty job candidates
had in producing even simple programs (simple as in should take a
minute
or less). One example was a program to print the numbers 1 to 100
except
that "Fizz" should be substituted for numbers divisible by 3, "Buzz"
should be substituted for numbers divisible by 5, and "FizzBuzz"
should
be substituted for numbers divisible by both 3 and 5.
UNQUOTE

For interest.

A type secure recursive solution in Qi
==================================

(define fizzbuzz
{number --> number --> symbol}
M N -> skip where (> M N)
M N -> (let Fizz (integer? (/ M 3))
Buzz (integer? (/ M 5))
Case (if (and Fizz Buzz) "FizzBuzz"
(if Fizz "Fizz"
(if Buzz "Buzz"
(make-string "~A" M))))
Print (output "~A~%" Case)
(fizzbuzz (+ M 1) N)))

** Now just to show you can do this in Qi. **

A type secure iterative solution
================================

(for M = 1 to 100
(let Fizz (integer? (/ M 3))
Buzz (integer? (/ M 5))
Case (if (and Fizz Buzz) "FizzBuzz"
(if Fizz "Fizz"
(if Buzz "Buzz"
(make-string "~A" M))))
(output "~A~%" Case)))

'for' is not in Qi. To create it map the above
to

(iterate (/. M (let Fizz (integer? (/ M 3))
Buzz (integer? (/ M 5))
Case (if (and Fizz Buzz) "FizzBuzz"
(if Fizz "Fizz"
(if Buzz "Buzz"
(make-string "~A" M))))
(output "~A~%" Case))) 1 100 (+ 1))

where 'iterate' is a higher order function of the following type

(define iterate
{(number --> A) --> number --> number --> (number --> number) -->
number}
F Min Max _ -> 0 where (> Min Max)
F Min Max Step -> (do (F Min) (iterate F (Step Min) Max Step)))

To compute the mapping and so add a type secure iterative 'for' into
Qi - add a sugar function (= macro) to do it for you

(define compile-for
[for X = Min to Max step Step Proc] -> [iterate [/. X Proc] Min Max
Step]
[for X = Min to Max Proc] -> [iterate [/. X Proc] Min Max [+ 1]]
X -> X)

(sugar in compile-for 0)

Test:

(17+) (for M = 1 to 100
(let Fizz (integer? (/ M 3))
Buzz (integer? (/ M 5))
Case (if (and Fizz Buzz) "FizzBuzz"
(if Fizz "Fizz"
(if Buzz "Buzz"
(make-string "~A" M))))
(output "~A~%" Case)))

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
.......
Buzz
0 : number


Some Comments
=============

This is easy to do in Qi but needs a good grasp of FP to do it. You
could undoubtedly add a type secure version of the CL LOOP too (and
probably write a paper on it). But ...

Generally **teaching newbies** this style is not great because it

a) delays their graduation into becoming mature functional
programmers
b) in the case of migration to other languages like ML or Haskell,
these resources will not be there and they will flounder.
c) annoys the hell out of their teacher/instructor who is trying to
teach Lisp from the Lisp 1.5 core (CONS, CAR, CDR).

I think some of these novice OPs would be much better off learning
about recursion and accumulators given the level of their questions.

Generally these procedural constructions are best revisited much
later, when the student can understand that they can be seen from a
new perspective.

Yes, ML etc. are very weak on the macro side. It is not a feature
that is inconsistent with static typing as the above demonstrates. It
is a design failure.

Mark

Raffael Cavallaro

unread,
May 31, 2011, 7:42:37 PM5/31/11
to
On 2011-05-31 07:57:05 -0400, Mark Tarver said:

> Yes, ML etc. are very weak on the macro side. It is not a feature
> that is inconsistent with static typing as the above demonstrates. It
> is a design failure.

Absolutely - there's no reason a well designed language can't have both
sorts of abstraction, functional and syntactic.

BTW, how is progress on Shen, the sucessor to Qi?

Raffael Cavallaro

unread,
May 31, 2011, 9:31:03 PM5/31/11
to
On 2011-05-31 19:42:37 -0400, Raffael Cavallaro said:

> BTW, how is progress on Shen, the sucessor to Qi?

Ah, google answers this question thus:

<http://www.lambdassociates.org/News/may11/index.htm>

0 new messages