Discussion:
: YC ( .. xt xt |0 -- .. ) BEGIN WHILE execute REPEAT ;
(too old to reply)
Gerry Jackson
2023-02-27 21:03:50 UTC
Permalink
On Friday, January 29, 2016 at 7:19:28 AM UTC, humptydumpty wrote:

: YC ( .. xt xt |0 -- .. ) BEGIN WHILE execute REPEAT ;
: xt latestxt postpone literal ; immediate
\ Use: : wordname .... test-sequence IF xt dup ELSE 0 THEN ;
\ Kick into action: ' wordname dup YC
: downcount dup . 1- dup 0 >= IF xt dup ELSE 0 THEN ;
10 ' downcount dup YC drop
---
*Factored* loop. Small. Beautiful. Deserves to be a primitive.
Enjoying forth,
humptydumpty
I've been experimenting with humptydumpty's (HD's) YC as defined above
and like the way it separates out the loop from the processing. However
LATESTXT is not a standard word and using YC is a bit messy.

A way around LATESTXT is to use a quotation, for example using HD's
DOWNCOUNT we can do:
: yc ( .. xt xt |0 -- .. ) BEGIN WHILE execute REPEAT ;

: (dc) ( n -- n-1 f ) dup . 1- dup 0 >= ;

0 value downcount-xt

: downcount
[: ['] (dc) execute if downcount-xt dup else 0 then ;]
dup dup to downcount-xt yc
;

10 downcount drop \ displays 10 9 8 7 6 5 4 3 2 1 0 ok

Still rather messy but shows the idea. Much of the body of DOWNCOUNT
would be common with other uses of YC and can be auto compiled so an
improved syntax is:

' (dc) iterator downcount
or of course
:noname dup . 1- dup 0 >= ; iterator downcount

where ITERATOR is a parsing word that compiles the equivalent of the
above code

A definition of ITERATOR using GForth's ]] ... [[ multi-postponer is:

: iterator ( "name" xt -- )
variable r@ >in !
: r> >in ! ' ( -- xt2 ) ( R: -- xt )
r ]] [: [[ r> r> compile, ( R: -- ) \ compile xt
dup >r compile, \ compile xt2
]] @ and ?dup [[ ( -- xt3 xt3|0 ) ( R: -- xt2 )
]] ;] dup dup [[
r> compile,
]] ! yc ; [[
;

1. A variable is used instead of a value as TO can't be postponed
2. downcount is parsed 3 times for the name of the variable, the name of
the iterating word and access to the variable
3. The stack diagram of the processing word e.g. (dc) is
(i*x -- j*y 0|-1), 0|-1 so that the IF statement can be replaced with
an AND

5 downcount drop 5 4 3 2 1 0 ok

The YC loops can be effectively nested and a processing pipeline formed
by code such as this simple example that replaces spaces in the input
stream with a '|' character. CATCH THROW are used simply to avoid the
verbose error messages Gforth displays when ABORT" is used.

: .word ( ca u -- 0|-1 )
dup if
2dup s" stop" compare 0=
if cr 99 throw then
type '|' emit
else
2drop
then
;
: (word) parse-name dup if .word -1 else 2drop cr 0 then ;
' (word) iterator next-word

: (line) refill if next-word -1 else 0 then ;
' (line) iterator next-line

: x cr ['] next-line catch 99 <> abort" Failed" ." Succeeded" ;
x
qwerty f hj asd qwerty|f|hj|asd|
'stop' will exit NEXT-LINE stop 'stop'|will|exit|NEXT-LINE|
Succeeded ok

I don't know why HD called it YC as it isn't a Y combinator but I don't
know what else is a good name.
--
Gerry
none) (albert
2023-02-28 12:55:11 UTC
Permalink
Post by Gerry Jackson
: YC ( .. xt xt |0 -- .. ) BEGIN WHILE execute REPEAT ;
: xt latestxt postpone literal ; immediate
\ Use: : wordname .... test-sequence IF xt dup ELSE 0 THEN ;
\ Kick into action: ' wordname dup YC
: downcount dup . 1- dup 0 >= IF xt dup ELSE 0 THEN ;
10 ' downcount dup YC drop
---
*Factored* loop. Small. Beautiful. Deserves to be a primitive.
Enjoying forth,
humptydumpty
I've been experimenting with humptydumpty's (HD's) YC as defined above
and like the way it separates out the loop from the processing. However
LATESTXT is not a standard word and using YC is a bit messy.
A way around LATESTXT is to use a quotation, for example using HD's
: yc ( .. xt xt |0 -- .. ) BEGIN WHILE execute REPEAT ;
: (dc) ( n -- n-1 f ) dup . 1- dup 0 >= ;
0 value downcount-xt
: downcount
[: ['] (dc) execute if downcount-xt dup else 0 then ;]
dup dup to downcount-xt yc
;
10 downcount drop \ displays 10 9 8 7 6 5 4 3 2 1 0 ok
Still rather messy but shows the idea. Much of the body of DOWNCOUNT
would be common with other uses of YC and can be auto compiled so an
' (dc) iterator downcount
or of course
:noname dup . 1- dup 0 >= ; iterator downcount
where ITERATOR is a parsing word that compiles the equivalent of the
above code
: iterator ( "name" xt -- )
: r> >in ! ' ( -- xt2 ) ( R: -- xt )
r ]] [: [[ r> r> compile, ( R: -- ) \ compile xt
dup >r compile, \ compile xt2
]] ;] dup dup [[
r> compile,
]] ! yc ; [[
;
1. A variable is used instead of a value as TO can't be postponed
2. downcount is parsed 3 times for the name of the variable, the name of
the iterating word and access to the variable
3. The stack diagram of the processing word e.g. (dc) is
(i*x -- j*y 0|-1), 0|-1 so that the IF statement can be replaced with
an AND
5 downcount drop 5 4 3 2 1 0 ok
The YC loops can be effectively nested and a processing pipeline formed
by code such as this simple example that replaces spaces in the input
stream with a '|' character. CATCH THROW are used simply to avoid the
verbose error messages Gforth displays when ABORT" is used.
: .word ( ca u -- 0|-1 )
dup if
2dup s" stop" compare 0=
if cr 99 throw then
type '|' emit
else
2drop
then
;
: (word) parse-name dup if .word -1 else 2drop cr 0 then ;
' (word) iterator next-word
: (line) refill if next-word -1 else 0 then ;
' (line) iterator next-line
: x cr ['] next-line catch 99 <> abort" Failed" ." Succeeded" ;
x
qwerty f hj asd qwerty|f|hj|asd|
'stop' will exit NEXT-LINE stop 'stop'|will|exit|NEXT-LINE|
Succeeded ok
I don't know why HD called it YC as it isn't a Y combinator but I don't
know what else is a good name.
As long as we're inventing syntax for loops,
the whole shebang of DO LOOP ?DO +LOOP has to be junked.
Remember in mathematics that [ .. ] and ( .. ) indicate an inclusive versus
an exclusive range.
[ 1 2 3 ] includes 1 and 3, ( 1 2 3 ) does not.

( n xt -- ) DO) \ Execute xt n times, lowest limit is default 0
( n xt -- ) DO] \ Execute xt n times, lowest limit is default 1
( l h xt -- ) DO[) \ Execute xt l-h times, with lowest and highest limits.
( l d h xt -- ) DO[..] \ Execute xt, as DO[] with increment d
Replace I with IX. Same number of words as previous, but more easy
to remember.
In order to do 10 spaces:
10 'SPACE DO)
10 'SPACE DO]
0 10 'SPACE DO[)
1 1 10 'SPACE DO[..]

Having promoted { } to signify both :NONAME and [: ;] we can do
10 { SPACE } DO)

This can be implemented with a few high level returns stack
manipulations.
And by the way. It works equally well in interpret mode.

Maybe add DO[] with now obvious meaning.
Post by Gerry Jackson
Gerry
Groetjes Albert
P.S. This comes about by at last have a lambda (denotation for
behaviour, i.e. { } ) gaining their civil rights.
--
Don't praise the day before the evening. One swallow doesn't make spring.
You must not say "hey" before you have crossed the bridge. Don't sell the
hide of the bear until you shot it. Better one bird in the hand than ten in
the air. First gain is a cat spinning. - the Wise from Antrim -
Loading...