[racket] Loop in Racket

1,799 views
Skip to first unread message

Brad Long

unread,
Jun 27, 2010, 9:32:00 PM6/27/10
to us...@racket-lang.org
Dear racketeers,

What is the reason for not offering a looping construct in racket? For
example, something like:

(loop (i 1 10) (print i))

Just for the masses, it seems simpler to use.

Any comments?

_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users

Robby Findler

unread,
Jun 27, 2010, 9:34:20 PM6/27/10
to Brad Long, us...@racket-lang.org
Please see 'for' in the docs. Here's the relevant section of the Guide:

http://docs.racket-lang.org/guide/for.html

Robby

Matthias Felleisen

unread,
Jun 27, 2010, 10:37:02 PM6/27/10
to Robby Findler, Brad Long, us...@racket-lang.org

Plus loops per se are evil -- opium for the masses if you so wish. -- Matthias

Neil Van Dyke

unread,
Jun 27, 2010, 10:46:49 PM6/27/10
to Brad Long, us...@racket-lang.org
FWIW, I like to assert that the familiar "FOR A = 1 TO 10" is actually
not often needed in idiomatic Scheme. More often, you're processing a
sequence, or you're doing functional programming such that you need to
recurse anyway to avoid mutation, or you need premature exits
sometimes. One possible exception that comes to mind is if you're
writing a matrix math library, but in that case you might make your own
procedures or syntax for iterating/folding over matrices in different ways.

Anyway, for the benefit of anyone new to syntax extensions, here is a
syntax definition that supports the "for-loop" example (warning: it
doesn't error-check as much as it should, because that would clutter the
example). You can paste this into DrRacket and use the Macro Stepper to
watch how it expands.


#lang scheme/base

(define-syntax for-loop
(syntax-rules ()
((_ (VAR START END) BODY0 BODY1 ...)
(let ((end-val END))
(let loop ((VAR START))
(if (> VAR end-val)
(void)
(begin BODY0 BODY1 ...
(loop (add1 VAR)))))))))

(for-loop (i 1 10) (print i))


Robby Findler wrote at 06/27/2010 09:34 PM:
> Please see 'for' in the docs. Here's the relevant section of the Guide:
>
> http://docs.racket-lang.org/guide/for.html
>
> Robby
>
> On Sun, Jun 27, 2010 at 8:32 PM, Brad Long <br...@longbrothers.net> wrote:
>
>> Dear racketeers,
>>
>> What is the reason for not offering a looping construct in racket? For
>> example, something like:
>>
>> (loop (i 1 10) (print i))
>>
>> Just for the masses, it seems simpler to use.
>>
>> Any comments?
>>

--
http://www.neilvandyke.org/

John Clements

unread,
Jun 27, 2010, 11:21:26 PM6/27/10
to Brad Long, Racket List

On Jun 27, 2010, at 6:32 PM, Brad Long wrote:

> Dear racketeers,
>
> What is the reason for not offering a looping construct in racket? For example, something like:
>
> (loop (i 1 10) (print i))
>

It's there:

(for/list ([i (in-range 1 10)]) i)

prints out

'(1 2 3 4 5 6 7 8 9)


... also, note that 'for/list' contains no opiates.

John

Stephen Bloch

unread,
Jun 28, 2010, 9:48:20 AM6/28/10
to Brad Long, us...@racket-lang.org
What is the reason for not offering a looping construct in racket? For
example, something like:

(loop (i 1 10) (print i))

Just for the masses, it seems simpler to use.

Simpler than what?  For what application?

The classic C/C++/Java "for" loop was designed for, and is almost always used for, integer counters stepping through an array.  In most of these applications, what you really want to do is "do something to each element of this array," or perhaps "do something to each element of this array until you find one that meets this criterion."

One of my general principles of programming is "try to avoid introducing concepts in the solution that weren't part of the problem."  In both of the above cases, the problem statement doesn't say anything about integer counters, indices, or mutation, so one should be able to solve the problem without those things.

In a low-level language like C or Pascal, one can't hide the fact that arrays are indexed with integers, and the way to do something with various different integers is a for-loop.  C++ starts to address the problem with "iterators", which still act like mutable counters and are still used in classic "for" loops, but at least they hide the array indexing.  Java does the same thing with "Iterable" and goes a step farther with "foreach" loops, which partially hide the mutation as well... but anyone who's ever tried defining a class that implements Iterable found that it still has to use mutation internally.  Scheme/Racket's list and sequence operations -- "map", "filter", "foldr", "for", "in-range", "in-naturals", "in-string", "stop-before", etc. -- are yet another step in the direction of eliminating concepts from the solution that weren't in the problem.

In other words, what's "simpler" is to use a construct that says what you mean.  If you want to print the integers 1 through 10 in increasing order (actually a fairly artificial problem whose main purpose is to test integer-counting for-loop constructs), use "for" and "in-range".  If you want to do something to each element of a list and get a list of the results, use "map".  If you want to extract the elements of a list that meet a particular criterion, use "filter".  If you want to count the elements of a list that meet a particular criterion, use "count-if".  And in the unlikely event that what you want to do doesn't match any of the defined constructs, Scheme/Racket allows you to write your own control constructs (indeed, I have assigned my CS0 students to write their own versions of "map", "filter", and "count-if").

Stephen Bloch
Reply all
Reply to author
Forward
0 new messages