Home > Archive > Lisp > June 2005 > Ugly loop
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
|
|
| Ulrich Hobelmann 2005-06-02, 8:58 pm |
| Hi, I just started coding what I always wanted to try out: doing
some stuff with finite automata and later regular expressions.
Right now I wrote a rather ugly loop to create an NFA from a
sequential string:
(loop with first = (make-instance 'state)
with nfa = (make-instance 'nfa :start-state first)
for c in (cons nil (loop for c across string collect c))
for source = first then target
for target = (make-instance 'state) then (make-instance 'state)
do (progn (add-state nfa source)
(link source c target))
finally (progn (add-state nfa target)
(setf (end-state nfa) target)
(return nfa))))
nil means a transition without any input.
Results look like this:
CL-USER> (print-nfa foo) ; from an input string "ab"
nfa: starts at G631
ends at G634
state G631
NIL -> G632
state G632
a -> G633
state G633
b -> G634
state G634
NIL
Any ideas how to make the loop cleaner and more elegant? This one
looks too much like Java code to me...
--
Don't let school interfere with your education. -- Mark Twain
| |
| Robert St Amant 2005-06-02, 8:58 pm |
| Ulrich Hobelmann <u.hobelmann@web.de> writes:
> Hi, I just started coding what I always wanted to try out: doing some
> stuff with finite automata and later regular expressions.
>
> Right now I wrote a rather ugly loop to create an NFA from a
> sequential string:
> (loop with first = (make-instance 'state)
> with nfa = (make-instance 'nfa :start-state first)
> for c in (cons nil (loop for c across string collect c))
> for source = first then target
> for target = (make-instance 'state) then (make-instance 'state)
> do (progn (add-state nfa source)
> (link source c target))
> finally (progn (add-state nfa target)
> (setf (end-state nfa) target)
> (return nfa))))
I think it looks reasonable. (The "then" part of "for target" is
redundant.) A different possibility is a recursive solution, if
you're unhappy with the iteration (untested, of course; hope there are
no stupid mistakes):
(let ((nfa (make-instance 'nfa :start-state (make-instance 'state)))
(label-list (cons nil (loop for c across string collect c))))
(labels ((extend-nfa (source target)
(add-state nfa source)
(cond (label-list
(link source (pop label-list) target)
(extend-nfa target (make-instance 'state)))
(t (add-state nfa target)
(setf (end-state nfa) target)))))
(extend-nfa (start-state nfa) (make-instance 'state))
nfa))
--
Rob St. Amant
http://www4.ncsu.edu/~stamant
| |
| Kenny Tilton 2005-06-03, 3:57 am |
|
Ulrich Hobelmann wrote:
> Hi, I just started coding what I always wanted to try out: doing some
> stuff with finite automata and later regular expressions.
>
> Right now I wrote a rather ugly loop to create an NFA from a sequential
> string:
> (loop with first = (make-instance 'state)
> with nfa = (make-instance 'nfa :start-state first)
> for c in (cons nil (loop for c across string collect c))
> for source = first then target
> for target = (make-instance 'state) then (make-instance 'state)
> do (progn (add-state nfa source)
> (link source c target))
> finally (progn (add-state nfa target)
> (setf (end-state nfa) target)
> (return nfa))))
It is commonplace to have something like add-state return the new state.
If you that:
(defun v1 (string)
(flet ((new-state () (make-instance 'state)))
(loop with nfa = (make-instance 'nfa :start-state (new-state))
for c in (cons nil (loop for c across string collect c))
for source = (start-state nfa) then target
for target = (new-state)
do
(link (add-state nfa source) c target)
finally
(setf (end-state nfa) (add-state nfa target))
(return nfa))))
Note that you do not need the progns.
State sounds simple, so I wager it can be a defstruct. That would give
us a make-state function. Then you can make the initform for start-state
be (make-state), and:
(defun v2 (string)
(loop with nfa = (make-instance 'nfa)
for c in (cons nil (loop for c across string collect c))
for source = (start-state nfa) then target
for target = (make-state)
do
(link (add-state nfa source) c target)
finally
(setf (end-state nfa) (add-state nfa target))
(return nfa)))
Anyway, I see room for a lot more improvement than that. I am bothered
by trying to blend initialization in with the looping, and I am
concerned about add-state not being called until a subsequent iteration.
Can you show us the link and add-state functions, as well as the nfa
defclass? ie, My goal is to get to v3:
(loop with nfa = (make-instance 'nfa)
for c across string
do (setf (input nfa) c) ;; see :after method on (setf input)
finally (return (nfa-terminate nfa))
Or even simpler. My thinking is that the machine should work by itself.
kt
--
Cells? : http://www.common-lisp.net/project/cells/
Cello? : http://www.common-lisp.net/project/cello/
Cells-Gtk? : http://www.common-lisp.net/project/cells-gtk/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"Doctor, I wrestled with reality for forty years, and I am happy to
state that I finally won out over it." -- Elwood P. Dowd
| |
| Pascal Bourguignon 2005-06-03, 3:57 am |
|
Kenny Tilton <ktilton@nyc.rr.com> writes:
> Note that you do not need the progns.
It's either the PROGNs or hacking emacs indenting...
(defun v1 (string)
(flet ((new-state () (make-instance 'state)))
(loop with nfa = (make-instance 'nfa :start-state (new-state))
for c in (cons nil (loop for c across string collect c))
for source = (start-state nfa) then target
for target = (new-state)
do (print c)
(link (add-state nfa source) c target)
finally (setf (end-state nfa) (add-state nfa target))
(return nfa))))
vs.:
(defun v1 (string)
(flet ((new-state () (make-instance 'state)))
(loop with nfa = (make-instance 'nfa :start-state (new-state))
for c in (cons nil (loop for c across string collect c))
for source = (start-state nfa) then target
for target = (new-state)
do (progn (print c)
(link (add-state nfa source) c target))
finally (progn (setf (end-state nfa) (add-state nfa target))
(return nfa)))))
--
__Pascal Bourguignon__ http://www.informatimago.com/
Small brave carnivores
Kill pine cones and mosquitoes
Fear vacuum cleaner
| |
| Kenny Tilton 2005-06-03, 3:57 am |
|
Pascal Bourguignon wrote:
> Kenny Tilton <ktilton@nyc.rr.com> writes:
>
>
>
> It's either the PROGNs or hacking emacs indenting...
Will you please stop blaming the world for your self-destructive
decision to save some loose change and use "free" crap that forever
sucks the blood out of you? (As if a hacked emacs would give you
anywhere near the productivity of a grown-up Lisp IDE.) Go ahead and use
your toy environment, but for chrissake do not ever suggest I degrade my
code to satisfy your lame environment.
:)
kt
ps. How hard would the emacs indenting be?
--
Cells? : http://www.common-lisp.net/project/cells/
Cello? : http://www.common-lisp.net/project/cello/
Cells-Gtk? : http://www.common-lisp.net/project/cells-gtk/
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"Doctor, I wrestled with reality for forty years, and I am happy to
state that I finally won out over it." -- Elwood P. Dowd
| |
| Thomas F. Burdick 2005-06-03, 9:07 am |
| Kenny Tilton <ktilton@nyc.rr.com> writes:
> Will you please stop blaming the world for your self-destructive
> decision to save some loose change and use "free" crap that forever
> sucks the blood out of you? (As if a hacked emacs would give you
> anywhere near the productivity of a grown-up Lisp IDE.) Go ahead and use
> your toy environment, but for chrissake do not ever suggest I degrade my
> code to satisfy your lame environment.
>
> :)
>
> kt
>
> ps. How hard would the emacs indenting be?
Not hard, just boring. And there exists some code that does it, but
it's of questionable ownership/legality to distribute.
Does any Lisp environment besides Allegro indent LOOP correctly?
--
/|_ .-----------------------.
,' .\ / | Free Mumia Abu-Jamal! |
,--' _,' | Abolish the racist |
/ / | death penalty! |
( -. | `-----------------------'
| ) |
(`-. '--.)
`. )----'
| |
| Espen Vestre 2005-06-03, 9:07 am |
| tfb@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> Does any Lisp environment besides Allegro indent LOOP correctly?
Not that I know of.
(I simply put do on a line on its own to increase readbility - a better
compromise than introducing bogus progns, I think)
--
(espen)
| |
| Edi Weitz 2005-06-03, 9:07 am |
| On 03 Jun 2005 00:46:03 -0700, tfb@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> Does any Lisp environment besides Allegro indent LOOP correctly?
AllegroCL does indent LOOP correctly? Using ELI? ELI is GPL AFAIK so
it should be possible to port this.
No, wait, Kenny uses Franz' NotePad emulation, right?
:)
Cheers,
Edi.
--
Lisp is not dead, it just smells funny.
Real email: (replace (subseq "spamtrap@agharta.de" 5) "edi")
| |
| Ulrich Hobelmann 2005-06-03, 9:07 am |
| Kenny Tilton wrote:
> It is commonplace to have something like add-state return the new state.
....
> Note that you do not need the progns.
Ok, that simplifies something.
> State sounds simple, so I wager it can be a defstruct. That would give
> us a make-state function. Then you can make the initform for start-state
> be (make-state), and:
Well, since Peter Seibel's book doesn't mention defstructs, I just
use classes. Probably they're more flexible as well, if I need to
change anything.
> (defun v2 (string)
> (loop with nfa = (make-instance 'nfa)
> for c in (cons nil (loop for c across string collect c))
> for source = (start-state nfa) then target
> for target = (make-state)
> do
> (link (add-state nfa source) c target)
> finally
> (setf (end-state nfa) (add-state nfa target))
> (return nfa)))
I noticed that I only put in the nil for the (useless) case of an
empty string, so I removed it again. I added an init-after method
to NFA and moved the add-state call into link:
(defclass nfa ()
((start-state :accessor start-state)
(end-state :accessor end-state)
(states :accessor states)))
(defmethod initialize-instance :after ((nfa nfa) &key)
(let ((state (make-instance 'state)))
(setf (start-state nfa) state
(end-state nfa) state
(states nfa) (list state))))
(defun add-state (nfa state)
(push state (states nfa))
state)
(defun link (nfa st1 input st2)
(push (make-instance 'transition :input input
:target (add-state nfa st2))
(transitions st1)))
and the loop:
(loop with nfa = (make-instance 'nfa)
for c across string
for source = (start-state nfa) then target
for target = (make-instance 'state)
do (link nfa source c target)
finally
(setf (end-state nfa) target)
(return nfa))
I'm quite happy with it so far. There is to see how it will
handle the other cases when I add them.
> Anyway, I see room for a lot more improvement than that. I am bothered
> by trying to blend initialization in with the looping, and I am
> concerned about add-state not being called until a subsequent iteration.
>
> Can you show us the link and add-state functions, as well as the nfa
> defclass? ie, My goal is to get to v3:
>
> (loop with nfa = (make-instance 'nfa)
> for c across string
> do (setf (input nfa) c) ;; see :after method on (setf input)
> finally (return (nfa-terminate nfa))
>
> Or even simpler. My thinking is that the machine should work by itself.
I'm not sure if that makes sense. I want to add other functions,
such as adding many parallel nodes instead of sequential nodes,
for alternatives. The SETF (INPUT ...) makes implicit from which
node the next transition goes. I'm not sure I want that.
Anyway, thanks a lot for the help and inspirations. I'll also
look up setf-after methods, just in case :)
--
Don't let school interfere with your education. -- Mark Twain
| |
| Marco Antoniotti 2005-06-03, 4:00 pm |
| There is some code around to extend cl-indent-function to handle LOOP in
a more sensible way. I just cannot find it. :) ACL probably has some
extra hacks to deal also with IF*.
Cheers
--
Marco
Edi Weitz wrote:
> On 03 Jun 2005 00:46:03 -0700, tfb@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
>
>
>
>
> AllegroCL does indent LOOP correctly? Using ELI? ELI is GPL AFAIK so
> it should be possible to port this.
>
> No, wait, Kenny uses Franz' NotePad emulation, right?
>
> :)
>
> Cheers,
> Edi.
>
| |
| Pascal Bourguignon 2005-06-03, 4:00 pm |
| Kenny Tilton <ktilton@nyc.rr.com> writes:
> Pascal Bourguignon wrote:
>
> Will you please stop blaming the world for your self-destructive
> decision to save some loose change and use "free" crap that forever
> sucks the blood out of you? (As if a hacked emacs would give you
> anywhere near the productivity of a grown-up Lisp IDE.) Go ahead and
> use your toy environment, but for chrissake do not ever suggest I
> degrade my code to satisfy your lame environment.
>
> :)
I take note. As soon as I'll be millionaire, I'd search one good
commercial IDE with features fullfiling my needs.
> kt
>
> ps. How hard would the emacs indenting be?
To do it correctly, you need an incremental parser.
Currently in emacs it's generally done with regexps, and moving around
the point, (using looking-at), and this is quite deficient because
correct indenting depends on the syntactic (and even sometimes
semantic) context.
Font-locking has similar problems. With an increment parser it would
be done at the same time as the indenting.
climacs does it properly. I could implement an increment parser in
emacs, but I've been wasted on Common-Lisp and I don't want to write
much emacs lisp anymore...
--
__Pascal Bourguignon__ http://www.informatimago.com/
You never feed me.
Perhaps I'll sleep on your face.
That will sure show you.
| |
| Matthias Buelow 2005-06-04, 3:57 pm |
| Ulrich Hobelmann wrote:
> Any ideas how to make the loop cleaner and more elegant? This one looks
> too much like Java code to me...
The only way to win loop is not to play it at all.
mkb.
| |
| Ulrich Hobelmann 2005-06-04, 8:57 pm |
| Matthias Buelow wrote:
> Ulrich Hobelmann wrote:
>
>
>
>
> The only way to win loop is not to play it at all.
Heh, well, sometimes I actually like loop despite its syntax.
Short, concise, and mostly it would take longer and result in less
readable code to use mapc / mapcar and other constructs.
--
Don't let school interfere with your education. -- Mark Twain
| |
| Matthias Buelow 2005-06-05, 3:57 am |
| Ulrich Hobelmann wrote:
> Heh, well, sometimes I actually like loop despite its syntax. Short,
> concise, and mostly it would take longer and result in less readable
> code to use mapc / mapcar and other constructs.
I think the following quote from Graham's ACL book hits the nail on the
head:
"The loop macro was originally designed to help inexperienced Lisp users
write iterative code. ... Unfortunately, loop is more like English than
its designers ever intended: you can use it in simple cases without
quite understanding how it works, but to understand it in the abstract
is almost impossible. ... almost no one understands it. ... you probably
never will, because the ANSI standard does not really give a formal
specification of its behaviour."
I've always been amazed to see how many code snippets posted on c.l.l
use loop. I would think that something that is so ugly and goes so
badly against the flow of Lisp would be a pariah construct but
apparently the loop virus finds new victims every year.
mkb.
| |
| Paul F. Dietz 2005-06-05, 3:57 am |
| Matthias Buelow wrote:
> I've always been amazed to see how many code snippets posted on c.l.l
> use loop. I would think that something that is so ugly and goes so
> badly against the flow of Lisp would be a pariah construct but
> apparently the loop virus finds new victims every year.
I've liked LOOP for decades. I've never understood the misplaced
puritanism that prefers incomprehensible DO or (shudder) LABELS
constructs. For the things that LOOP does well, its competitors
are manifestly inferior.
Paul
| |
| Matthias Buelow 2005-06-05, 3:57 am |
| Paul F. Dietz wrote:
> I've liked LOOP for decades. I've never understood the misplaced
> puritanism that prefers incomprehensible DO or (shudder) LABELS
> constructs. For the things that LOOP does well, its competitors
> are manifestly inferior.
Well, I'm only using Lisp for a couple years but I certainly do prefer
LABELS and Scheme-style recursion instead of DO (which I always get
wrong on the first attempt) or the abominable (imho) LOOP. There're
quite a few dark corners in Common Lisp and if I were to redesign it,
LOOP would be the first to go.
mkb.
| |
| Paul F. Dietz 2005-06-05, 3:57 am |
| Matthias Buelow wrote:
> Well, I'm only using Lisp for a couple years but I certainly do prefer
> LABELS and Scheme-style recursion instead of DO (which I always get
> wrong on the first attempt) or the abominable (imho) LOOP.
What can I say? You're wrong. :)
Doing Scheme in Lisp is another pet peeve of mine, btw.
Paul
| |
| Matthias Buelow 2005-06-05, 3:57 am |
| Paul F. Dietz wrote:
> Doing Scheme in Lisp is another pet peeve of mine, btw.
What I'd like would be something in between Scheme and Common Lisp. Not
as stiff and rigid and puritan as Scheme (for example, I like
dynamically scoped "special" variables and the straightforward Common
Lisp macro system) but not as monstrous and inconsistent and full of
archaeological baggage as Common Lisp. Unfortunately such a thing
doesn't seem to exist. Well, maybe Graham's Arc will go in that
direction, once it's out (I hope he'll make it open source).
mkb.
| |
| Kenny Tilton 2005-06-05, 3:57 am |
|
Paul F. Dietz wrote:
> Matthias Buelow wrote:
>
>
>
> What can I say? You're wrong. :)
I will say more in reaching the same conclusion.
To MB: You are not wrong. I was anti-Loop for almost a decade. then with
the help of PCL I broke down and learned it (something or other on
c.l.l. persuaded me to give it another try). Now I do not like using
anything else.
Again, you are not wrong. Loop is not Lisp. (nb: Loop does have a Lispy
alternative syntax.) But iterating comes up enough that the Loop
mini-language is worth learning.
Don't forget: Graham is wrong about CLOS, too. :)
--
Kenny
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"If you plan to enter text which our system might consider to be
obscene, check here to certify that you are old enough to hear the
resulting output." -- Bell Labs text-to-speech interactive Web page
| |
| Pascal Costanza 2005-06-05, 8:56 am |
| Matthias Buelow wrote:
> Ulrich Hobelmann wrote:
>
>
> I think the following quote from Graham's ACL book hits the nail on the
> head:
>
> "The loop macro was originally designed to help inexperienced Lisp users
> write iterative code. ... Unfortunately, loop is more like English than
> its designers ever intended: you can use it in simple cases without
> quite understanding how it works, but to understand it in the abstract
> is almost impossible. ... almost no one understands it. ... you probably
> never will, because the ANSI standard does not really give a formal
> specification of its behaviour."
This quote foremostly means that Paul Graham doesn't understand it.
> I've always been amazed to see how many code snippets posted on c.l.l
> use loop. I would think that something that is so ugly and goes so
> badly against the flow of Lisp would be a pariah construct but
> apparently the loop virus finds new victims every year.
LOOP can lead to very compact and very easily understandable code. I
don't care about the dark corners of LOOP, because I can just avoid
them. There are cases when I switch to recursive versions of an
iteration when LOOP loses its steam, but this rarely happens. (And I
still have to learn ITERATE which seems to solve many problems that LOOP
has.)
LOOP doesn't work from first principles. For some people, this is hard
to grasp because they expect programming language design to be some
mathematical exercise, but that's nonsense. [1] In the case of LOOP,
it's important to get rid of this preconception and to learn it just by
practising it. You may not be willing to do that, but don't
overgeneralize your own preconceptions, then.
Pascal
[1] A programming language is a human-computer interface, with the
central idea that it should be designed for the human to be able to
better express ideas. If this weren't the case, assembler would be
enough. In some areas of language design, a mathematically sound basis
helps, but that doesn't make it a general principle.
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Pascal Costanza 2005-06-05, 8:56 am |
| Matthias Buelow wrote:
> Paul F. Dietz wrote:
>
>
> Well, I'm only using Lisp for a couple years but I certainly do prefer
> LABELS and Scheme-style recursion instead of DO (which I always get
> wrong on the first attempt) or the abominable (imho) LOOP. There're
> quite a few dark corners in Common Lisp and if I were to redesign it,
> LOOP would be the first to go.
See also http://ccs.mit.edu/papers/CCSWP150.html ;)
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Pascal Costanza 2005-06-05, 8:56 am |
| Matthias Buelow wrote:
> Paul F. Dietz wrote:
>
>
>
>
> What I'd like would be something in between Scheme and Common Lisp. Not
> as stiff and rigid and puritan as Scheme (for example, I like
> dynamically scoped "special" variables and the straightforward Common
> Lisp macro system) but not as monstrous and inconsistent and full of
> archaeological baggage as Common Lisp. Unfortunately such a thing
> doesn't seem to exist.
You may want to take a look at ISLISP.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Alan Crowe 2005-06-05, 8:56 am |
| Matthias Buelow:
> There're quite a few dark corners in Common Lisp and if I
> were to redesign it, LOOP would be the first to go.
That would be a disaster. The Loopies would use DEFMACRO to
put LOOP back, except that they would take the opportunity
to make their own favourite modifications. Instead of one
LOOP to complain about there would be a hundred subtlely
incompatible variants.
Once a language designer puts DEFMACRO into his language he
gives up the power to exclude constructs he doesn't
like. The /best/ he can do is to provide good standard
versions of the constructs he doesn't like so that they
don't ramify. Ouch.
Alan Crowe
Edinburgh
Scotland
| |
| David Golden 2005-06-05, 3:57 pm |
| Paul F. Dietz wrote:
> For the things that LOOP does well, its competitors
> are manifestly inferior.
>
I'd be interested to hear how so in the particular case of the iterate
package? (apart from the triviality of loop being in the current ANSI
spec and iterate being an add-on package..). My current thinking is
that loop should be probably be deprecated and iter added to base
cl :-)
| |
| Paul F. Dietz 2005-06-05, 3:57 pm |
| David Golden wrote:
> I'd be interested to hear how so in the particular case of the iterate
> package?
It's not standardized. :)
Paul
| |
| Edi Weitz 2005-06-05, 3:58 pm |
| On Sun, 05 Jun 2005 12:43:58 +0100, David Golden <david.golden@oceanfree.net> wrote:
> Paul F. Dietz wrote:
>
>
> I'd be interested to hear how so in the particular case of the
> iterate package? (apart from the triviality of loop being in the
> current ANSI spec and iterate being an add-on package..).
That's /not/ a triviality. If you allow any old third-party package
then you can certainly write something that is nicer than LOOP,
especially with hindsight. The /real/ competitors are DO/DO*, MAPC,
etc.
> My current thinking is that loop should be probably be deprecated
> and iter added to base cl :-)
Sure, please open up a new standardization process... :)
Cheers,
Edi.
--
Lisp is not dead, it just smells funny.
Real email: (replace (subseq "spamtrap@agharta.de" 5) "edi")
| |
| Alexander Schmolck 2005-06-05, 3:58 pm |
| Matthias Buelow <mkb@incubus.de> writes:
> Paul F. Dietz wrote:
>
>
> What I'd like would be something in between Scheme and Common Lisp.
Have you tried plt+swindle?
'as
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Kenny Tilton wrote:
> To MB: You are not wrong. I was anti-Loop for almost a decade. then with
> the help of PCL I broke down and learned it (something or other on
> c.l.l. persuaded me to give it another try). Now I do not like using
> anything else.
I must admit to not having read PCL so far (since I don't have the time
atm.) A cursory look at the online version shows that he introduces
loop pretty early. Also many snippets to new-user questions on c.l.l
use it. That's what I find a bit problematic. If you introduce new
users to loop early, it's like giving them eval right from the
beginning: you'll end up with programs that are basically loop forms
with a bit of ordinary lisp around them. Same with eval: it's too
easily abused by people who do not (yet) know what they're doing. An
experienced user may use loop (or rarely, eval) without doing much harm,
since he knows when to use it (and when not) but for a new user this
looks too much like a panacea to solve all his iteration (and recursion)
needs, just like eval tempts new users to abuse it by constructing forms
on the fly and feeding them to eval. IMHO new lisp users should start
with recursion for doing loops, and ordinary list functions (mapc,
mapcar, apply, ...), and understand them well, and then use iteration
constructs like do, dolist, and only then get introduced -- with
appropriate warnings -- to the loop facility.
mkb.
| |
| Wade Humeniuk 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> I must admit to not having read PCL so far (since I don't have the time
> atm.) A cursory look at the online version shows that he introduces
> loop pretty early. Also many snippets to new-user questions on c.l.l
> use it. That's what I find a bit problematic. If you introduce new
> users to loop early, it's like giving them eval right from the
> beginning: you'll end up with programs that are basically loop forms
> with a bit of ordinary lisp around them. Same with eval: it's too
> easily abused by people who do not (yet) know what they're doing. An
> experienced user may use loop (or rarely, eval) without doing much harm,
> since he knows when to use it (and when not) but for a new user this
> looks too much like a panacea to solve all his iteration (and recursion)
> needs, just like eval tempts new users to abuse it by constructing forms
> on the fly and feeding them to eval. IMHO new lisp users should start
> with recursion for doing loops, and ordinary list functions (mapc,
> mapcar, apply, ...), and understand them well, and then use iteration
> constructs like do, dolist, and only then get introduced -- with
> appropriate warnings -- to the loop facility.
>
Yes, oh mighty dictator! We bow to your altar of wisdom... we
cannot have people just doing whatever they want. (lead us not
into temptations...)
Wade
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Wade Humeniuk wrote:
> Yes, oh mighty dictator! We bow to your altar of wisdom... we
> cannot have people just doing whatever they want. (lead us not
> into temptations...)
Eh? I was just arguing from a didactical point of view. If you want to
criticize this, then please do it in a more substantial way than just
dropping bullshit.
mkb.
| |
| Wade Humeniuk 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Wade Humeniuk wrote:
>
>
>
>
> Eh? I was just arguing from a didactical point of view. If you want to
> criticize this, then please do it in a more substantial way than just
> dropping bullshit.
>
Well.... No, can't help myself, I am a bull after all. You are
bound for an early grave with such a serious controlling attitude.
If you could also redesign c.l.l would I also be the first to go?
Wade
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Wade Humeniuk wrote:
> Well.... No, can't help myself, I am a bull after all. You are
> bound for an early grave with such a serious controlling attitude.
> If you could also redesign c.l.l would I also be the first to go?
You can't seem to stand opinions being voiced that are different from yours.
mkb.
| |
| Kenny Tilton 2005-06-05, 3:58 pm |
|
Matthias Buelow wrote:
> Wade Humeniuk wrote:
>
>
>
>
> Eh? I was just arguing from a didactical point of view. If you want to
> criticize this, then please do it in a more substantial way than just
> dropping bullshit.
Sorry, this is comp.lang.lisp, and we are The Savages Thereof. Bullshit
is as sophisticated as we get. If you want nice manners, try the pointy
heads over in comp.lang.scheme.
But seriously folks, I had the same reaction as Wade: humans generally
screw up when they overthink things. I should not as a teacher set
myself so high as to try to save students from abuse I am only imagining
they might make of a feature. You concern is plausible (loop forms qua
programs) but does not justify hiding a construct from students who
might apply it judiciously, and benefit from the advantages of loop.
Better to let Nature take its course and just lay the language out there
and let the chips fall where they may. Holdiong back on loop will not
keep abusuers from abusing it anyway.
--
Kenny
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"If you plan to enter text which our system might consider to be
obscene, check here to certify that you are old enough to hear the
resulting output." -- Bell Labs text-to-speech interactive Web page
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Kenny Tilton wrote:
> Better to let Nature take its course and just lay the language out there
> and let the chips fall where they may. Holdiong back on loop will not
> keep abusuers from abusing it anyway.
But surely you'd want to teach students good programming techniques
first, and only then give them the cheats?
mkb.
| |
| Pascal Costanza 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> I must admit to not having read PCL so far (since I don't have the time
> atm.) A cursory look at the online version shows that he introduces
> loop pretty early. Also many snippets to new-user questions on c.l.l
> use it. That's what I find a bit problematic. If you introduce new
> users to loop early, it's like giving them eval right from the
> beginning: you'll end up with programs that are basically loop forms
> with a bit of ordinary lisp around them. Same with eval: it's too
> easily abused by people who do not (yet) know what they're doing.
This is not a good comparison (and by your own standards too confusing
for beginners). EVAL can lead to problems because it allows you to
execute code on the metalevel, and it's important to understand the
difference between base level and metalevel in order to know what you're
doing when you use EVAL. Nothing exists that remotely resembles these
issues in the case of LOOP vs other iteration constructs.
LOOP is a good example of a 'domain-specific' language designed to solve
certain tasks well while leaving other tasks untouched. I don't see why
it would be a bad message to encourage thinking in terms of
domain-oriented abstractions.
> An
> experienced user may use loop (or rarely, eval) without doing much harm,
> since he knows when to use it (and when not) but for a new user this
> looks too much like a panacea to solve all his iteration (and recursion)
> needs, just like eval tempts new users to abuse it by constructing forms
> on the fly and feeding them to eval. IMHO new lisp users should start
> with recursion for doing loops, and ordinary list functions (mapc,
> mapcar, apply, ...), and understand them well, and then use iteration
> constructs like do, dolist, and only then get introduced -- with
> appropriate warnings -- to the loop facility.
Is this a claim, a conjecture, or an empirical assessment? Can you back
this with references to existing literature?
Or is it that you just don't like LOOP and try to impose your personal
preferences on others?
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Jack Unrue 2005-06-05, 3:58 pm |
| On Sun, 05 Jun 2005 16:47:28 +0200, Matthias Buelow <mkb@incubus.de> wrote:
>
> I must admit to not having read PCL so far (since I don't have the time
> atm.) A cursory look at the online version shows that he introduces
> loop pretty early. Also many snippets to new-user questions on c.l.l
> use it. That's what I find a bit problematic. If you introduce new
> users to loop early, it's like giving them eval right from the
> beginning: you'll end up with programs that are basically loop forms
> with a bit of ordinary lisp around them. Same with eval: it's too
> easily abused by people who do not (yet) know what they're doing. An
> experienced user may use loop (or rarely, eval) without doing much harm,
> since he knows when to use it (and when not) but for a new user this
> looks too much like a panacea to solve all his iteration (and recursion)
> needs, just like eval tempts new users to abuse it by constructing forms
> on the fly and feeding them to eval. IMHO new lisp users should start
> with recursion for doing loops, and ordinary list functions (mapc,
> mapcar, apply, ...), and understand them well, and then use iteration
> constructs like do, dolist, and only then get introduced -- with
> appropriate warnings -- to the loop facility.
>
Lisp is all about exploratory programming, right? I'd say new users (like
myself) ought to experiment, and then we can decide for ourselves.
--
Jack
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Pascal Costanza wrote:
>
> Is this a claim, a conjecture, or an empirical assessment? Can you back
> this with references to existing literature?
It is a conjecture, resulting from applying common sense. Why should
one teach something that is a) not properly defined, b) ambiguous and c)
totally different in style and workings than the rest of Common Lisp to
a new learner of that language, who wants to get a grasp on the
essentials and the general feeling of the language first, and not on
its, to put it mildly, fanciful outgrowths.
If one could inline a subset of BASIC into Common Lisp, because someone
somewhen deemed that practical for a certain application, would you also
teach beginners BASIC instead of Lisp?
mkb.
| |
| Pascal Costanza 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Kenny Tilton wrote:
>
>
> But surely you'd want to teach students good programming techniques
> first, and only then give them the cheats?
Define "good programming techniques".
The discussion boils down to this: What makes you think that you have
seen the light? Your students may not even stick to Lisp...
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Paul F. Dietz 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Eh? I was just arguing from a didactical point of view. If you want to
> criticize this, then please do it in a more substantial way than just
> dropping bullshit.
A didactical point of view that assumes your prejudice
reflects an actual problem.
Paul
| |
| Pascal Costanza 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Pascal Costanza wrote:
>
>
> It is a conjecture, resulting from applying common sense.
See http://en.wikipedia.org/wiki/Common_sense for an overview of "common
sense".
> Why should
> one teach something that is a) not properly defined, b) ambiguous and c)
> totally different in style and workings than the rest of Common Lisp to
> a new learner of that language, who wants to get a grasp on the
> essentials and the general feeling of the language first, and not on
> its, to put it mildly, fanciful outgrowths.
a) LOOP is properly defined. See the ANSI specification.
b) Show us problems you had with LOOP's purported ambiguities. Maybe
someone can help you.
(I think Ulrich found the original discussion in this thread helpful. Do
you seriously suggest not to respond when someone asks a LOOP-specific
question? Apparently yes, given your original statement in this thread.)
c) It's good to show people that you can mix very different programming
styles in one language. That's the whole idea of a multi-paradigm language.
My impression is that you are an advocate of single-paradigm
programming. This is an arguable position to take, but very problematic
because it has a tendency not to accept diverging positions. You can
find advocates of single-paradigm "right-thing" programming in almost
all camps (functional, object-oriented, logic, imperative, static,
dynamic, etc. pp.). They rarely have good rational arguments, except
that their respectively preferred approach is supposedly "obviously"
superior.
They can't all be true. I think none of them is.
So, yes, I think it's a good idea to show people early on that Common
Lisp doesn't force you at all to think in, or use a certain programming
style.
> If one could inline a subset of BASIC into Common Lisp, because someone
> somewhen deemed that practical for a certain application, would you also
> teach beginners BASIC instead of Lisp?
That's a straw man. Noone claimed to exclusively teach LOOP.
It could make a good case study for showing how to embed a specific
language into Common Lisp, though.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Paul F. Dietz 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> It is a conjecture, resulting from applying common sense. Why should
> one teach something that is a) not properly defined, b) ambiguous and c)
> totally different in style and workings than the rest of Common Lisp to
> a new learner of that language, who wants to get a grasp on the
> essentials and the general feeling of the language first, and not on
> its, to put it mildly, fanciful outgrowths.
Because (a) it is properly defined, in practice(*), (b) is not ambiguous,
as actually used, and (c) more concise and understandable than the
alternatives in Common Lisp.
Loop fills a gap. If you don't like it, well, it's your loss, Matthias.
Paul
(*) There are some problems with corner cases here and there, but that's
true of many other parts of the CL standard as well. Deal with it.
| |
| Kenny Tilton 2005-06-05, 3:58 pm |
|
Matthias Buelow wrote:
> Kenny Tilton wrote:
>
>
>
>
> But surely you'd want to teach students good programming techniques
> first, and only then give them the cheats?
Cheat?! It is in the spec, probably because it was deemed to be not just
some random hack, but rather a solid extension to Lisp.
Anyway, the didactic arrow can point in the other direction (other than
simple-first, fancy-later) as often. Sometimes we convey as much power
as painlessly as possible (your so-called "cheats"), and hide ugly
details until (a) some momentum has developed and (b) the higher order
construct breaks down and we need grittier stuff.
btw, I believe the thing that got me to look at loop was that it
provides efficiency for free, which is rare in cheats:
(loop for x in them
when (yada x)
collect x)
vs:
(let (out)
(dolist (x them (nreverse out))
(when (yada x) (push x out)
If I had learned Lisp from PCL I would have grown up with loop as a
native sub-language and not gone seven years without it. As it was, I
knew the do family and was able to get by with that, so why kill a day
learning what looked to be a tangled mess of a sublanguage?
So maybe loop is like skating or skiing: start 'em young so they grow up
with it.
--
Kenny
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"If you plan to enter text which our system might consider to be
obscene, check here to certify that you are old enough to hear the
resulting output." -- Bell Labs text-to-speech interactive Web page
| |
| Wade Humeniuk 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Wade Humeniuk wrote:
>
>
>
>
> You can't seem to stand opinions being voiced that are different from yours.
>
Yes, my Master. Together we shall end this destructive Lisp conflict and
bring peace and order to the galaxy ....
Hoping to be a new Darth and Laughing On a Sunday Morning!
Wade
| |
| Cameron MacKinnon 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> IMHO new lisp users should start
> with recursion for doing loops, and ordinary list functions (mapc,
> mapcar, apply, ...), and understand them well, and then use iteration
> constructs like do, dolist, and only then get introduced -- with
> appropriate warnings -- to the loop facility.
Should they be taught about the possibility that a given Lisp
implementation may or may not optimize tail recursion? Absent
guarantees, teaching Lisp recursion is teaching a non-portable
technique, as code which runs fine in one Lisp may exhaust memory in
another, and code which runs fine for small input may fail for large
input, even though there's no obvious input size dependencies in the code.
| |
| Tayssir John Gabbour 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Pascal Costanza wrote:
>
>
> It is a conjecture, resulting from applying common sense. Why should
> one teach something that is a) not properly defined, b) ambiguous and c)
> totally different in style and workings than the rest of Common Lisp to
> a new learner of that language, who wants to get a grasp on the
> essentials and the general feeling of the language first, and not on
> its, to put it mildly, fanciful outgrowths.
My question: is iteration complicated enough that LOOP is appropriate?
I think yes. The universe never guaranteed that it could be neatly
described by an aesthetically "Lispish" form.
In fact, I recall someone found keyword arguments "unlispy" either.
Well, many parts of the world don't bend for Lisp. I personally find
LAMBDA repugnant, and it's part of a main alternative to LOOP. Here's a
user anecdote:
"After trying to 'self-learn' lisp in the 80's I get this physical
reaction to the word 'lambda'...a cold sweat combined with the
involuntary retraction of my testicles to a protected location in my
abdomen (damn unpleasant shit)..."
http://slashdot.org/article.pl?sid=...&mode=nocomment
It's a pretentious and lazy name whose purpose in life is to turn
people off to a simple concept, of building little lexical bubbles.
But LOOP? Well, there may be some design problems in it that's fixed by
ITERATE, but I still like LOOP a lot. Think of it as a witticism, a
humorous expression; in particular "loop for key being the hash-keys of
hash using (hash-value val)". That's your programming tool having
character. None of this paved-over Java corporate crap, which is
uniform so commodity coders can be plugged into it.
> If one could inline a subset of BASIC into Common Lisp, because someone
> somewhen deemed that practical for a certain application, would you also
> teach beginners BASIC instead of Lisp?
If BASIC were better than Lisp, most certainly.
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Pascal Costanza wrote:
> c) It's good to show people that you can mix very different programming
> styles in one language. That's the whole idea of a multi-paradigm language.
The "multi-paradigm" way of programming by using macros to extend the
language makes no sense to someone who hasn't yet understood macros. To
understand how loop (and similar constructs) work, you have to
understand macros. For a beginner, who doesn't yet know (much) about
macros, loop is an opaque puzzle, and he'll probably believe it is
special syntax like in other programming languages and hence gets a
completely wrong picture of the language. The good thing about Lisp is
that it can be taught from the ground up, starting with basic things
like conses, a few primitive operators, functions and recursion, and
building the rest of the language on top of it. That way a beginner
will get a thorough grasp of the language. If you just throw all the
finished stuff at him/her, in a how-to or recipe-style way, imho the
student will be a lot more .
mkb.
| |
| Matthias Buelow 2005-06-05, 3:58 pm |
| Cameron MacKinnon wrote:
> Should they be taught about the possibility that a given Lisp
> implementation may or may not optimize tail recursion? Absent
> guarantees, teaching Lisp recursion is teaching a non-portable
> technique, as code which runs fine in one Lisp may exhaust memory in
> another, and code which runs fine for small input may fail for large
> input, even though there's no obvious input size dependencies in the code.
They should be taught that a good compiler does employ tail
optimization, and that they should dump the rest that doesn't.
mkb.
| |
| Pascal Costanza 2005-06-05, 3:58 pm |
| Matthias Buelow wrote:
> Pascal Costanza wrote:
>
>
> The "multi-paradigm" way of programming by using macros to extend the
> language makes no sense to someone who hasn't yet understood macros. To
> understand how loop (and similar constructs) work, you have to
> understand macros. For a beginner, who doesn't yet know (much) about
> macros, loop is an opaque puzzle, and he'll probably believe it is
> special syntax like in other programming languages and hence gets a
> completely wrong picture of the language. The good thing about Lisp is
> that it can be taught from the ground up, starting with basic things
> like conses, a few primitive operators, functions and recursion, and
> building the rest of the language on top of it. That way a beginner
> will get a thorough grasp of the language. If you just throw all the
> finished stuff at him/her, in a how-to or recipe-style way, imho the
> student will be a lot more .
I spare my "claim, conjecture, assessment" question this time, and hope
you have read the article about common sense.
I don't think that people learn like you seem to suggest. At least when
learning natural languages, it's better to use a top-down approach than
a bottom-up approach. So first learn how to speak, then how to write,
and finally the grammar and how this all is knitted together. You just
don't start by first explaining the Saphir-Whorf-Hypothesis.
Or compare this to mathematics: The first thing you learned was adding
numbers, not category theory, right?
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Cameron MacKinnon 2005-06-05, 3:58 pm |
| Tayssir John Gabbour wrote:
> My question: is iteration complicated enough that LOOP is appropriate?
> I think yes. The universe never guaranteed that it could be neatly
> described by an aesthetically "Lispish" form.
Iteration is certainly complicated enough to be a source of many bugs in
code written in many computer languages. It's complicated enough that
Scheme's inventors took a radically different approach to it. It's
complicated enough that there will likely never be consensus among
Lispers about the best construct to express it with.
> I personally find
> LAMBDA repugnant...
> It's a pretentious and lazy name whose purpose in life is to turn
> people off to a simple concept, of building little lexical bubbles.
That's the result, not the original purpose. It's an artifact of
primitive early computers that a symbol which could be written with two
quick strokes of the pencil (and which rather resembled mathematics'
canonical symbol for the generic placeholder) turned into an ugly
looking six keystrokes signifying nothing.
--
Cameron MacKinnon
Toronto, Canada
| |
| Tayssir John Gabbour 2005-06-05, 3:58 pm |
| Tayssir John Gabbour wrote:
> Matthias Buelow wrote:
>
> My question: is iteration complicated enough that LOOP is appropriate?
> I think yes. The universe never guaranteed that it could be neatly
> described by an aesthetically "Lispish" form.
>
> In fact, I recall someone found keyword arguments "unlispy" either.
> Well, many parts of the world don't bend for Lisp.
That was Stallman, incidentally, who was a prolific Lisp Machine
developer. I can't find the cite easily though, and I suspect I read
that in a context where he explained he eventually changed his mind.
| |
| Ulrich Hobelmann 2005-06-05, 8:57 pm |
| Matthias Buelow wrote:
> Wade Humeniuk wrote:
>
>
>
>
> Eh? I was just arguing from a didactical point of view. If you want to
> criticize this, then please do it in a more substantial way than just
> dropping bullshit.
Speaking for myself: I used Scheme for some time and SML after
that, so I'm definitely used to recursion instead of looping. In
my first CL program I started using mapcar and mapc in some
places, but now I rewrote them as LOOPs to make them clearer (with
one exception: loop for ex in (mapcar ...)).
To me loop looks like a perfect solution to general iteration
problems, while I'd use mapcar over loop for simple mappings in an
instant.
I think both iteration and recursion are natural in real-world
programming and should be both be stressed for beginners. Clearly
most (good) CS texts, for instance SICP, focus more on the
recursion part, as that's where most beginners have problems
(maybe because in Java iteration is the gold standard, and
recursion at least painful).
--
Don't let school interfere with your education. -- Mark Twain
| |
| Richard M Kreuter 2005-06-05, 8:57 pm |
| Matthias Buelow <mkb@incubus.de> writes:
> Why should one teach something that is a) not properly defined, b)
> ambiguous and c) totally different in style and workings than the
> rest of Common Lisp to a new learner of that language, who wants to
> get a grasp on the essentials and the general feeling of the
> language first, and not on its, to put it mildly, fanciful
> outgrowths.
Primarily because nobody is exposed to Common Lisp as a first
language; they've already got a head full of ideas about how
programming works. And so there are several answers to your question:
* Because the learner comes from languages with convenient constructs
for iteration that fit nicely with those languages' data types, and
you want them to understand that Lisp has analogous constructs.
* Because do/do* requires a lot of parentheses, which will probably
only confirm most parenthophobes' fears of Lisp.
* Because if you don't, then the learner who hasn't yet understood the
use of higher order functions is liable to write things like this:
(dotimes (i (floor (/ (1+ (length some-list)) 2)))
(let ((obj (nth (* 2 i) some-list)))
<body> ))
instead of this
(loop for obj in some-list by #'cddr
do <body> )
If they write code like the former, they'll "learn" that Lisp is
slow. (They shouldn't be using lists for much of anything either,
but they're going to anyhow.) And remember, the latest spin on why
CL is is that it's an unbounded superset of the languages that
a novice will already know, so we can't just say "Don't write
iterative code for walking lists; you must use map and functions."
* Because exposing a learner to sublanguages embedded in Lisp will
convey the notion that Lisp can mix-n-match lots of different
idioms, and gives an early opportunity to explain that one can add
powerful, expressive language extensions, like loop.
--
Richard
| |
| Matthias Buelow 2005-06-05, 8:57 pm |
| Richard M Kreuter wrote:
> * Because if you don't, then the learner who hasn't yet understood the
> use of higher order functions is liable to write things like this:
>
> (dotimes (i (floor (/ (1+ (length some-list)) 2)))
> (let ((obj (nth (* 2 i) some-list)))
> <body> ))
>
> instead of this
>
> (loop for obj in some-list by #'cddr
> do <body> )
I'd present higher-order functions pretty early. Then the learner might
come up with something like the following.
He'd perhaps write a general purpose utility, which is also useful for
future use:
(defun step-list (l s f)
(let ((o (funcall s l)))
(if (car o)
(progn
(funcall f (car o))
(step-list o s f)))))
And then he could use it like:
(step-list '(1 2 3 4 5 6 7 8 9 10 11 12) #'cddr #'princ)
instead of
(loop for obj in '(1 2 3 4 5 6 7 8 9 10 11 12) by #'cddr do (princ obj))
Granted, the loop is faster to write for a one-shot solution of that
kind but as soon as you'd use that construct a second time, the first
approach is faster, and easier to understand.
That's also a problem I sometimes find when reading Lisp source: Instead
of constructing utility functions (and macros), and assembling
algorithms from these utilities, some people write the logics in form of
endlessly nested LOOPs (or DO or whatever), with the result that it is
truly horrible to read, compared to programming by combining
meaningfully named functions.
mkb.
| |
| Pascal Costanza 2005-06-05, 8:57 pm |
| Matthias Buelow wrote:
> I'd present higher-order functions pretty early. Then the learner might
> come up with something like the following.
>
> He'd perhaps write a general purpose utility, which is also useful for
> future use:
>
> (defun step-list (l s f)
> (let ((o (funcall s l)))
> (if (car o)
> (progn
> (funcall f (car o))
> (step-list o s f)))))
>
> And then he could use it like:
>
> (step-list '(1 2 3 4 5 6 7 8 9 10 11 12) #'cddr #'princ)
>
> instead of
>
> (loop for obj in '(1 2 3 4 5 6 7 8 9 10 11 12) by #'cddr do (princ obj))
>
> Granted, the loop is faster to write for a one-shot solution of that
> kind but as soon as you'd use that construct a second time, the first
> approach is faster, and easier to understand.
These two "solutions" are not even remotely similar:
? (step-list '(t 1 nil 2 t 3) #'cddr #'print)
NIL
? (loop for obj in '(t 1 nil 2 t 3) by #'cddr
do (print obj))
T
NIL
T
NIL
Now before correcting one of the two versions, please ask yourself first
the following question: Which of the two is better understandable wrt
what it is supposed to do?
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Matthias Buelow 2005-06-05, 8:57 pm |
| Pascal Costanza wrote:
> the following question: Which of the two is better understandable wrt
> what it is supposed to do?
Of course the above is a trivial example. If you look at Ulrich's
original loop (as posted in his original posting that started this
thread) the scene is a lot different. 1-clause loops are simple and
easy to understand; it's the loops that use many clauses that soon
degenerate into an incomprehensible mess.
mkb.
| |
| david.tolpin@gmail.com 2005-06-05, 8:57 pm |
|
> These two "solutions" are not even remotely similar:
>
> ? (step-list '(t 1 nil 2 t 3) #'cddr #'print)
> NIL
> ? (loop for obj in '(t 1 nil 2 t 3) by #'cddr
> do (print obj))
>
> T
> NIL
> T
> NIL
>
> Now before correcting one of the two versions, please ask yourself first
> the following question: Which of the two is better understandable wrt
> what it is supposed to do?
Both are beyond understanding; If you want to say 'every other', say it
in clear words: reduce the list by printing only those at even
positions:
(reduce #'(lambda (odd val) (case odd ((nil) (print val) t) (t nil)))
'(t 1 nil 2 t 3) :initial-value nil)
T
NIL
T
NIL
David
| |
| Pascal Costanza 2005-06-05, 8:57 pm |
| Matthias Buelow wrote:
> Pascal Costanza wrote:
>
>
> Of course the above is a trivial example. If you look at Ulrich's
> original loop (as posted in his original posting that started this
> thread) the scene is a lot different. 1-clause loops are simple and
> easy to understand; it's the loops that use many clauses that soon
> degenerate into an incomprehensible mess.
Speak for yourself. I haven't had any serious problems understanding
Ulrich's LOOP, and others who actually discussed it didn't seem to either.
The only messy code so far in this thread is your recursive step-list.
So you have not only not backed your claims with actual evidence or some
good rationale, you have even provided an actual counter example to your
own claims.
There is a broad range of cases where LOOP is concise, clearly expresses
what is happening, and furthermore produces efficient code. LOOP takes
some time to understand, but it's worth it. To me, these look like very
good reasons to explain it to people who may be interested.
If you have good reasons for abandoning LOOP, you should actually start
to present them.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Matthias Buelow 2005-06-05, 8:57 pm |
| Pascal Costanza wrote:
> If you have good reasons for abandoning LOOP, you should actually start
> to present them.
Why should I justify _not_ using it to anyone? I don't say that you
should stop using it. I only say that I don't recommend using it.
This whole thread must be quite bizarre for any outsider; I mean, I can
imagine that arguments like this were made already 20 years ago.
Thankfully I'm not dependent on Common Lisp programming (or other
people's LOOP-infested code), so this whole thing is to me, like someone
else already described it, a "pet peeve".
mkb.
| |
| Paul F. Dietz 2005-06-06, 3:58 am |
| Matthias Buelow wrote:
>
> Why should I justify _not_ using it to anyone?
You wrote:
[...] if I were to redesign [Common Lisp],
LOOP would be the first to go.
This is 'abandoning' LOOP. Now, are you objecting to
us insisting that you justify your position?
Paul
| |
| Tayssir John Gabbour 2005-06-06, 3:58 am |
| Pascal Costanza wrote:
> Matthias Buelow wrote:
>
This might be less buggy and more in the (pseudo?) function-oriented
style:
(defun step-list (step-function list)
"The bizarro world's FILTER/REMOVE. Don't question why it always adds
its first element to the result."
(if list
(cons (first list)
(step-list step-function (funcall step-function list)))
nil))
(mapcar #'princ (step-list #'cddr '(1 2 3 4 5 6 7 8 9 10 11 12)))
prints:
1357911
Now, let's keep in mind that if I were a real functional guy, I'd
probably use Series or even Qi instead of bothering with built-in Lisp.
;)
[color=darkred]
> These two "solutions" are not even remotely similar:
>
> ? (step-list '(t 1 nil 2 t 3) #'cddr #'print)
> NIL
> ? (loop for obj in '(t 1 nil 2 t 3) by #'cddr
> do (print obj))
>
> T
> NIL
> T
> NIL
>
> Now before correcting one of the two versions, please ask yourself first
> the following question: Which of the two is better understandable wrt
> what it is supposed to do?
A few advantages of function-oriented style:
* Debugging: tools like TRACE
* Debugging: unreadability of macroexpanded LOOPs.
* Maybe less messing around with state... though the statefulness of
LOOP may be overestimated.
Some di vantages:
* Recursion may mix the looping mechanisms messily into the normal
code.
* You often keep naming things to recurse on them, which leads to
problems if you keep renaming things and don't use some Leitao-ish
refactoring browser.
* Is function-oriented programming a readability silver bullet? When
things get big 'n nasty, does it stay pristine?
* Is it general? If not, there's a testing burden for each little util
you write.
* May require one to combine multiple concepts like IF, PROGN, FUNCALL
and CAR, as in Matthias's example above.
* May have (tail) recursion problems.
* Is so hot with multiple datatypes? Well, maybe there's some CLOS
solution.
Tayssir
| |
| Matthias Buelow 2005-06-06, 3:58 am |
| Paul F. Dietz wrote:
> This is 'abandoning' LOOP. Now, are you objecting to
> us insisting that you justify your position?
That's a purely hypothetical context; as for the reason, I think it's
redundant and horrible, is that enough?
[Of course LOOP would be joined by pathnames, and other cruft. I don't
want to go into detail in fear of opening more fronts here and it's
purely hypothetical anyways. I don't really care either.]
mkb.
| |
| Matthias Buelow 2005-06-06, 3:58 am |
| Tayssir John Gabbour wrote:
> A few advantages of function-oriented style:
> * Debugging: tools like TRACE
> * Debugging: unreadability of macroexpanded LOOPs.
> * Maybe less messing around with state... though the statefulness of
> LOOP may be overestimated.
One more advantage:
If you think of programming as some kind of verb-object relationship,
you can write clearer code since you can name the verbs. With things
like LOOP (or DO, etc.) the verbs are unexpressive; they are "LOOP" and
its clause keywords, or "DO", etc. The meaning has to be inferred by
the naming of objects (symbol names) alone. With functional
programming, the verbs (often) get proper names that describe what
operation they perform (if the programmer cares about good naming
discipline).
mkb.
| |
| Kenny Tilton 2005-06-06, 3:58 am |
|
Paul F. Dietz wrote:
> Matthias Buelow wrote:
>
>
>
> You wrote:
>
> [...] if I were to redesign [Common Lisp],
> LOOP would be the first to go.
>
> This is 'abandoning' LOOP. Now, are you objecting to
> us insisting that you justify your position?
Hey, this is a generally intelligent thread, no "gotcha" games over an
obvious bit of hyperbowl, please.
--
Kenny
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"If you plan to enter text which our system might consider to be
obscene, check here to certify that you are old enough to hear the
resulting output." -- Bell Labs text-to-speech interactive Web page
| |
| Kenny Tilton 2005-06-06, 3:58 am |
|
Pascal Costanza wrote:
> Matthias Buelow wrote:
>
>
>
> Speak for yourself. I haven't had any serious problems understanding
> Ulrich's LOOP, and others who actually discussed it didn't seem to either.
Speak for yourself yourself. :) We understood it, but it was horrid,
which is why Ulrich asked for input. In an act of typical cll savagery I
asked about the overall algorithm, and Ulrich obtained nice gains in
readability by reworking the bigger picture.
Exercise for the reader Mathias: rewrite the original as DO or DO*.
Contrast and compare.
--
Kenny
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
"If you plan to enter text which our system might consider to be
obscene, check here to certify that you are old enough to hear the
resulting output." -- Bell Labs text-to-speech interactive Web page
| |
| Cameron MacKinnon 2005-06-06, 3:58 am |
| Paul F. Dietz wrote:
> Matthias Buelow wrote:
>
>
>
> You wrote:
>
> [...] if I were to redesign [Common Lisp],
> LOOP would be the first to go.
>
> This is 'abandoning' LOOP. Now, are you objecting to
> us insisting that you justify your position?
If he doesn't object, I will. "LOOP sucks" isn't a breathtaking new
theory which should require the marshalling of great bodies of evidence
and a spirited defense. It's a sentiment which has been shared and
credibly defended over the decades by various Lisp hackers of high
repute. If you want to know what they said about it, you're free to read
the aforementioned Graham, to peruse The Art of the Interpreter or to
use your favourite search engine to see more reasoning used by those who
hold the opinion.
There is likely nothing new or interesting to be gained by asking the
holder of such a commonly held opinion why he holds it. "LOOP rocks" is
also a common sentiment, one whose defenders' evidence has been on
display for just as long. Pick a camp, and agree to disagree.
--
Cameron MacKinnon
Toronto, Canada
| |
| Tayssir John Gabbour 2005-06-06, 3:58 am |
| Matthias Buelow wrote:
> Paul F. Dietz wrote:
>
> That's a purely hypothetical context; as for the reason, I think it's
> redundant and horrible, is that enough?
>
> [Of course LOOP would be joined by pathnames, and other cruft. I don't
> want to go into detail in fear of opening more fronts here and it's
> purely hypothetical anyways. I don't really care either.]
First LOOP, then pathnames, then "Why not the Jews?" I think we all
know where this reasoning leads.
Unfortunately, you're posting this from a .de address, making this
comment heavier than I intend...
| |
| Matthias Buelow 2005-06-06, 3:58 am |
| Tayssir John Gabbour wrote:
>
> First LOOP, then pathnames, then "Why not the Jews?" I think we all
> know where this reasoning leads.
The point is that pathnames are (imho) a remnant from, and stuck in, the
80ies (like so many things in Common Lisp). Today, I'd probably use URIs
as strings, together with a library for constructing them and taking
them apart in all possible ways, and doing mappings from/to the
underlying system's convention.
> Unfortunately, you're posting this from a .de address, making this
> comment heavier than I intend...
Maybe you (subconsciously) just wanted to invoke Hitler in order to end
this thread instantly, as is customary on Usenet.
mkb.
| |
| Adrian Kubala 2005-06-06, 3:58 am |
| Kenny Tilton <ktilton@nyc.rr.com> schrieb:
> (loop for x in them
> when (yada x)
> collect x)
>
> vs:
>
> (let (out)
> (dolist (x them (nreverse out))
> (when (yada x) (push x out)
What about : (filter #'yada them)
I'm not sure why people are doing so much explicit iteration when map,
fold and friends cover almost everything already.
| |
| Tayssir John Gabbour 2005-06-06, 3:58 am |
| Matthias Buelow wrote:
> Tayssir John Gabbour wrote:
>
> The point is that pathnames are (imho) a remnant from, and stuck in, the
> 80ies (like so many things in Common Lisp). Today, I'd probably use URIs
> as strings, together with a library for constructing them and taking
> them apart in all possible ways, and doing mappings from/to the
> underlying system's convention.
>
>
> Maybe you (subconsciously) just wanted to invoke Hitler in order to end
> this thread instantly, as is customary on Usenet.
I don't care, though I suspect you feel attacked by the conversation
here. Which I hope is not the case. (But the net is depersonalizing.)
Perhaps you perceive people being fundamentalist on what seems to be a
trivial issue; but there's more than meets the eye about LOOP.
For some people, seeing the good in LOOP is something like a backlash
against the fundamentalist, aesthetic ideologies which plague the
computing world.
Further, there's this rather maddening stigma Lisp has as being all
about functions+lists. It's a real timewaster for many.
Someone on this thread once explained to me that a person's reaction to
LOOP tells you something about her. ;) I think there's a lot to that
idea. Not that LOOP is perfect or another religion, but rather that
person at least has passed one or two ideological obstacles.
But who knows. This is a little thing in many ways.
Tayssir
| |
| Matthias Buelow 2005-06-06, 3:58 am |
| Tayssir John Gabbour wrote:
> Someone on this thread once explained to me that a person's reaction to
> LOOP tells you something about her. ;) I think there's a lot to that
> idea. Not that LOOP is perfect or another religion, but rather that
> person at least has passed one or two ideological obstacles.
So what you basically claim is that someone who likes loop is on an
intellectually higher level than someone who doesn't.
mkb.
| |
| Dan Muller 2005-06-06, 3:58 am |
| Matthias Buelow <mkb@incubus.de> writes:
> Pascal Costanza wrote:
>
>
> Why should I justify _not_ using it to anyone? I don't say that you
> should stop using it. I only say that I don't recommend using it.
There seems a good reason for pursuing the matter. IIRC, you are a
teacher, and have stated that your opinion of LOOP influences your
teaching. Thus your opinion is not merely personal preference; it
will likely be adopted by many of your students. This raises the
stakes a bit.
> This whole thread must be quite bizarre for any outsider; I mean, I can
> imagine that arguments like this were made already 20 years ago.
Probably not, if the outsider is a programmer who's passionate about
some language. Similar debates over language features are legion on
the net.
| |
| Matthias Buelow 2005-06-06, 3:58 am |
| Dan Muller wrote:
> There seems a good reason for pursuing the matter. IIRC, you are a
> teacher, and have stated that your opinion of LOOP influences your
> teaching. Thus your opinion is not merely personal preference; it
No, I'm not. Lisp is nothing but a hobby for me.
mkb.
| |
| Pascal Costanza 2005-06-06, 8:57 am |
| Matthias Buelow wrote:
> Pascal Costanza wrote:
>
>
> Why should I justify _not_ using it to anyone? I don't say that you
> should stop using it. I only say that I don't recommend using it.
You have suggested to hide LOOP from newbies and to remove it from the
standard if this were possible. That goes a little bit further than just
not using it yourself, and should therefore be more substantially
justified. [1]
Apart from that: Go ahead, do what you like. Noone forces you to use LOOP.
Pascal
[1] Especially because the Common-Lisp-like dialect that doesn't have
LOOP already exists!
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Pascal Costanza 2005-06-06, 8:57 am |
| Kenny Tilton wrote:
>
>
> Pascal Costanza wrote:
>
>
> Speak for yourself yourself. :) We understood it, but it was horrid,
> which is why Ulrich asked for input.
I didn't claim it was especially beautiful... ;)
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Pascal Costanza 2005-06-06, 8:57 am |
| Tayssir John Gabbour wrote:
> This might be less buggy and more in the (pseudo?) function-oriented
> style:
>
> (defun step-list (step-function list)
> "The bizarro world's FILTER/REMOVE. Don't question why it always adds
> its first element to the result."
> (if list
> (cons (first list)
> (step-list step-function (funcall step-function list)))
> nil))
This is not tail-recursive. In each recursion, CONS will wait for its
arguments to return values.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| Pascal Costanza 2005-06-06, 8:57 am |
| Cameron MacKinnon wrote:
> If he doesn't object, I will. "LOOP sucks" isn't a breathtaking new
> theory which should require the marshalling of great bodies of evidence
> and a spirited defense. It's a sentiment which has been shared and
> credibly defended over the decades by various Lisp hackers of high
> repute. If you want to know what they said about it, you're free to read
> the aforementioned Graham, to peruse The Art of the Interpreter or to
> use your favourite search engine to see more reasoning used by those who
> hold the opinion.
What are the search terms to use to find these numerous reasonings? I
have only found one: http://www.paulgraham.com/loop.html - which seems
to suggest that they have just aimed very high and haven't reached all
their goals. I can live with that.
At last year's European Lisp and Scheme Workshop, the great majority
admitted to use LOOP regularly. (Sven-Olof Nystroem asked the 40
participants to raise their hands for several iteration constructs. LOOP
seems to be strongly favored over other constructs by that "sample
group". And they didn't seem to be unhappy about it.)
"The Art of the Interpreter" doesn't talk about LOOP.
> There is likely nothing new or interesting to be gained by asking the
> holder of such a commonly held opinion why he holds it. "LOOP rocks" is
> also a common sentiment, one whose defenders' evidence has been on
> display for just as long. Pick a camp, and agree to disagree.
We are not just discussing which camp to pick. If this were all this is
about, I wouldn't mind.
Pascal
--
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
| |
| david.tolpin@gmail.com 2005-06-06, 8:57 am |
| > Well, I'm only using Lisp for a couple years but I certainly do prefer
> LABELS and Scheme-style recursion instead of DO (which I always get
> wrong on the first attempt) or the abominable (imho) LOOP. There're
> quite a few dark corners in Common Lisp and if I were to redesign it,
> LOOP would be the first to go.
LOOP is a domain specific language created using Lisp's macro facility.
One of applications of the DSL approach is to create domain languages
for those who can't use the full power of Lisp and only need it for a
limited subset of tasks. LOOP allows programmers who can't write clean
iteration code in Lisp concisely to catch common cases using LOOP's
domain specific language.
Otherwise, they would write code which is worse than the most horrible
loop.
A real Lisp programmer has a better generic Lisp alternative to LOOP
for general cases, and writes a DSL for his domain with specific
iteration constructs. Those who can't do either, use LOOP.
David
| |
| Thomas F. Burdick 2005-06-06, 8:57 am |
| Matthias Buelow <mkb@incubus.de> writes:
> Kenny Tilton wrote:
>
>
> But surely you'd want to teach students good programming techniques
> first, and only then give them the cheats?
You're absolutely right. Teaching new students how to use the
existing structures that come with the language will only encourage
them to depend on decades of others' experience. Better to have them
build up their own structures from the start. No LOOP, no DO, no
LABELS. For Purity, give them LAMBDA with which they can build their
own Y combinator and with that all else. For Clarity, give them
TAGBODY and GO (or maybe cheat and give them all of PROG) with which
they can build their own loops.
(I'm only half-kidding about PROG, maybe this would help stop the
abuse of boolean state variables in loops)
--
/|_ .-----------------------.
,' .\ / | Free Mumia Abu-Jamal! |
,--' _,' | Abolish the racist |
/ / | death penalty! |
( -. | `-----------------------'
| ) |
(`-. '--.)
`. )----'
| |
| Matthias 2005-06-06, 8:57 am |
| Matthias Buelow <mkb@incubus.de> writes:
> The good thing about Lisp is that it can be taught from the ground
> up, starting with basic things like conses, a few primitive
> operators, functions and recursion, and building the rest of the
> language on top of it. That way a beginner will get a thorough
> grasp of the language. If you just throw all the finished stuff at
> him/her, in a how-to or recipe-style way, imho the student will be a
> lot more .
I also happen to think that this is a strong point of lisp. But note
that Practical Common Lisp was not written with the beginning
programmer in mind (as were SICP or HtdP) but with a
medium-experienced programmer who is new to CL. I think it's ok not
to bother these people overly with explaining recursion, functions,
etc before getting to the "practical" stuff.
Esp. since SICP already does an excellent job in teaching programming
with lisp in a more fundamental way.
| |
| Espen Vestre 2005-06-06, 8:57 am |
| Pascal Costanza <pc@p-cos.net> writes:
> LOOP can lead to very compact and very easily understandable code. I
> don't care about the dark corners of LOOP, because I can just avoid
> them. There are cases when I switch to recursive versions of an
> iteration when LOOP loses its steam, but this rarely happens. (And I
> still have to learn ITERATE which seems to solve many problems that
> LOOP has.)
I tend to move things to DO-clauses when the conditionals get too
complicated, since complex IF-THEN-ELSE clauses in LOOP IMHO easily
can get unreadble (I recently uttered som loop-scepticism here because
after a bad debugging experience due to complex conditionals).
But IMHO the main shortcoming of loop is that it isn't complete
enough. For instance, LOOP would be even more fun if it had general
sequence accumulation and not only list and number accumulation - I'm
tired of writing e.g. (coerce (loop ... collect ...) 'string)!
> [1] A programming language is a human-computer interface, with the
> central idea that it should be designed for the human to be able to
> better express ideas.
Well, the "provable programs" or even "programs that prove their own
correctness" discipline has had a large impact on many computer
science departments. The mathematical logician in me is somewhat
attracted to those ideas - the hacker in me detests them. Common Lisp
is a good blend of precision, high quality standards and pragmatism,
i.e. just what the dual-natured logician-hacker needs :-)
--
(espen)
| |
| Paolo Amoroso 2005-06-06, 8:57 am |
| Pascal Costanza <pc@p-cos.net> writes:
> Cameron MacKinnon wrote:
>
[...][color=darkred]
> What are the search terms to use to find these numerous reasonings? I
You may try something like this with Google:
knee-jerk anti-loopism lisp
which should return references to discussions on LOOP during ANSI
Common Lisp standardization. See for example:
Knee-jerk Anti-LOOPism and other E-mail Phenomena:
Oral, Written, and Electronic Patterns in Computer-Mediated Communication
http://ccs.mit.edu/papers/CCSWP150.html
The ANSI CL working group mailing list archives should provide more
in depth material.
Paolo
--
Why Lisp? http://lisp.tech.coop/RtL%20Highlight%20Film
Recommended Common Lisp libraries/tools (see also http://clrfi.alu.org):
- ASDF/ASDF-INSTALL: system building/installation
- CL-PPCRE: regular expressions
- UFFI: Foreign Function Interface
| |
| Lars Brinkhoff 2005-06-06, 8:57 am |
| "david.tolpin@gmail.com" <david.tolpin@gmail.com> writes:
> Both are beyond understanding; If you want to say 'every other', say it
> in clear words: reduce the list by printing only those at even
> positions:
>
> (reduce #'(lambda (odd val) (case odd ((nil) (print val) t) (t nil)))
> '(t 1 nil 2 t 3) :initial-value nil)
Or use this trick:
(mapc (lambda (x y)
(when y (print x)))
'(1 2 3 4 5 6 7 8 9)
'#1=(t nil . #1#))
| |
| Alain Picard 2005-06-06, 8:57 am |
| Matthias Buelow <mkb@incubus.de> writes:
> Why should
> one teach something that is [blah blah blah]
> to a new learner of that language, who wants to get a grasp on the
> essentials and the general feeling of the language first, [SNIP]
The book is called _Practical_ Common Lisp.
Loop is, well, practical. Heck, some even think it useful!
| |
| Stefan Ram 2005-06-06, 3:58 pm |
| "david.tolpin@gmail.com" <david.tolpin@gmail.com> writes:
>A real Lisp programmer has a better generic Lisp alternative to LOOP
>for general cases, and writes a DSL for his domain with specific
>iteration constructs. Those who can't do either, use LOOP.
(abstract: About a translator from an S-expression-like
language to Java, which also includes custom iteration
constructs.)
I have a Java-library, which can read my variant of
S-expressions (this variant is called "Unotal"). In order to
gain some experience with it, I started to try to write Java
using Unotal, and then to translate this to Java using a
program called "Metava".
Just for fun, I introduce ad-hoc notations, whenever they
please me, including loop-constructs such as the following:
emitIndentation =<< &repeat times=indentation < &write [" "] >>>
Metava translates this to:
public static void
emitIndentation
()
{
for
( int i = indentation; i-- > 0; )java.lang.System.out.print
( " " ); }
I also have a default value for "times", which is "it". When
a function has a parameter, but not a parameter name, the
parameter will also be called "it". So here is another input:
emitLine=< from=int < &repeat < &line >>< | | |