On Sunday, January 31, 2016 at 12:02:41 PM UTC-6, humptydumpty wrote:
> Hi!
>
> For users sake, I think is good thing to have the same stack effect
> for all kinds of loops. I don't tested for speed any of them.
> Of course, this is Forth and everyone can rewrite them for his/her needs.
>
> : XT latestxt postpone literal ; immediate
> : ?YC postpone IF postpone XT postpone ELSE 0 postpone LITERAL postpone THEN ; immediate
> \ --- 9 LOOPS
> : YC ( .. xt|0 -- .. ) BEGIN ?dup WHILE execute REPEAT ;
> : YCC ( .. xt|0 -- .. ) DO execute LOOP drop ;
> : YCC+ ( .. xt|0 -- .. ) DO execute +LOOP drop ;
> : YCCI ( .. xt|0 -- .. ) DO I swap execute LOOP drop ;
> : YCCI+ ( .. xt|0 -- .. ) DO I swap execute +LOOP drop ;
> : YCG ( .. xt|0 -- .. ) DO ?dup IF execute ELSE unloop exit THEN LOOP drop ;
> : YCG+ ( .. xt|0 -- .. ) DO ?dup IF execute ELSE unloop exit THEN +LOOP drop ;
> : YCGI ( .. xt|0 -- .. ) DO ?dup IF I swap execute ELSE unloop exit THEN LOOP drop ;
> : YCGI+ ( .. xt|0 -- .. ) DO ?dup IF I swap execute ELSE unloop exit THEN +LOOP drop ;
>
> Cons: slower than original loop, especially for small loops.
> Pro: enforce factoring, easy testing: 'execute .S' is all that is
> needed to test the word to be fed to a factored-loop.
>
> Enjoying forth,
> humptydumpty
Thanks for this list of words. I didn't like your YC , and this
list helped me to say why.
I know, when I start to write a word, whether it'll have a loop
or not. Then it's just a question of whether I want to use DO
or not. If I'm basically iterating over an array - there is a
start and endpoint and they are connected by definite increments
from one to other - then I use DO. Otherwise, BEGIN.
I don't say, I'll use one of BEGIN ... WHILE ... REPEAT or else
BEGIN ... UNTIL or else BEGIN ... AGAIN. Because these are all
really just conveniences upon BEGIN ... AGAIN. If you need to
do some post-loop work then you can EXIT to a caller that does
it or you can branch past the loop to do it.
And likewise I don't *think* about which variants of DO ... LOOP
I want. It just works out that the code requires one of them.
So I approach the word with an understanding that it'll be
looping, I decide on DO or BEGIN , and then I no longer care
about looping structures, I just care about what the word
requires.
With your words, I would have to ask: do I want YC, or YCC, or
YCC+, or YCCI, or YCCI+, or YCG, or YCG+, or YCGI, or YCGI+ .
Even if I'd memorized all of these, I would still have to decide
between them. And I still have to decide between them before I
write the body of the loop, because it must pass flags or
increments to them.
Of factoring, instead of having a bunch of words that work
together to form loops, you have a fixed list of different kinds
of loops that don't work with each other. And the words are
still tightly bound to what would be the body of the loop: you
can't just switch YC and YCC and get a different looping
behavior, for example. And the those original words have a lot
of value that's lost: you can no longer EXIT or UNLOOP EXIT and
you can't just put -> I <- precisely wherever it's needed and if
you have what would be a BEGIN loop you can't put state on the
return stack before the loop begins, access it during the loop,
and grab it after the loop.
On teaching, if I were to teach Forth, even at the level of
answering an isolated question about looping, I would say what I
said above: when you start to write a looping word, ask these
questions. But if Forth only had YC words I would have to say
"well, memorize these words and and the fine differences between
them".
On the look of the language, DO I LOOP isn't so pretty, but it
at least uses short real words that you can say to someone
instead of spelling them out. The BEGIN words can actually look
pretty good. YCG+ is of course "why see gee plus" and you might
fail to distinguish between it and YCC+.
-- Julian