• Re: : YC ( .. xt xt |0 -- .. ) BEGIN WHILE execute REPEAT ;

    From Gerry Jackson@21:1/5 to humptydumpty on Mon Feb 27 21:03:50 2023
    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

    \ Example:
    : 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 -- )
    >in @ 2>r ( R: -- xt n )
    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

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From none) (albert@21:1/5 to do-not-use@swldwa.uk on Tue Feb 28 13:55:11 2023
    In article <ttj5rm$3batb$1@dont-email.me>,
    Gerry Jackson <do-not-use@swldwa.uk> wrote:
    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

    \ Example:
    : 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 -- )
    >in @ 2>r ( R: -- xt n )
    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.

    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.

    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 -

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)