• Iterator using [ELSE]

    From Gerry Jackson@[email protected] to comp.lang.forth on Tue Nov 4 21:36:40 2025
    From Newsgroup: comp.lang.forth

    HunptyDumpty introduced his Y Combinator in this post: https://groups.google.com/g/comp.lang.forth/c/ea59-OtiLvE/m/TH_8t9c7BgAJ
    with the definition
    : yc ( .. xt xt |0 -- .. ) begin while execute repeat ;

    An example from HD's post:
    : downcount dup . 1- dup 0 >= IF xt dup ELSE 0 THEN ;
    where xt is the execution token of downcount.

    Having experimented with iterators to avoid having to get the xt of a
    word I tried using a quotation:

    : foo [: <body of downcount> ;] yc ;

    and developed a word ITERATOR-YC to generate the boiler-plate code
    around a word such as DOWNCOUNT. This was rather complicated.

    After that I realised that moving the BEGIN from YC to precede the
    quotation led to a more flexible iterator in that the code inside the quotation can exit in three ways
    1. naturally at the end of the quotation with TRUE on the stack
    2. EXIT with 0 on the stack to exit the iterator
    3. EXIT with TRUE on the stack to prematurely start another iteration.

    Much like a multi-WHILE loop but better.

    Last week in the Conditional Compilation discussion, having shown how
    [ELSE] could be used as a general purpose word to skip over lines of
    text or code e.g. for a multi-line comment, I realised that this could
    greatly simplify ITERATOR-YC so that a definition for DOWNCOUNT could be defined as:

    iterator: downcount dup 0< if drop 0 exit then dup . 1- true ;iterator

    where iterator: ... ;iterator compiles the following code

    : downcount true begin [: dup 0< if drop 0 exit then dup . 1- true :]
    swap while execute repeat drop
    ;

    The implementation follows
    \ ------------------------

    : ]] \ Single line postponer, avoids POSTPONE clutter
    begin
    >in @ parse-name s" [[" compare
    while
    >in ! postpone postpone
    repeat drop
    ; immediate

    \ Ruvim's reference code for [IF] [THEN] [ELSE]
    wordlist dup constant bracket-flow-wl get-current swap set-current

    : [if] ( level1 -- level2 ) 1+ ;
    : [else] ( level1 -- level2 ) dup 1 = if 1- then ;
    : [then] ( level1 -- level2 ) 1- ;

    : ;iterator 1- ;
    : \ postpone \ ;

    set-current

    : [else] ( -- )
    1 begin begin parse-name
    dup while
    bracket-flow-wl search-wordlist if
    execute dup 0= if drop exit then
    then
    repeat 2drop refill 0= until drop

    : [then] ( -- ) ; immediate

    : [if] ( flag -- ) 0= if postpone [else] then ; immediate

    \ The iterator compiler

    synonym scan-words [else]

    : iterator: ( "name" -- xt ) \ xt of quotation
    : ]] true begin [: [[
    save-input ]] scan-words [[ restore-input
    abort" Error: RESTORE-INPUT failed"
    ;

    : ;iterator ( xt -- ) ]] ;] swap while execute repeat drop ; [[ ;
    immediate

    \ Example
    iterator: downcount dup 0< if drop 0 exit then dup . 1- true ;iterator

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

    \ ------------------------

    Note this code will only work from a file as SAVE-INPUT is not
    guaranteed to work from a keyboard.

    ITERATOR: starts the definition and quotation, then SAVE-INPUT
    and SCAN-WORDS scan past the quotation code until the first definition
    of ;ITERATOR stops the scanning.
    RESTORE-INPUT returns control to the start of the downcount code which
    compiles the downcound code until the second definition of ;ITERATOR
    compiles the rest of the boiler-plate code.

    A definition of [ELSE] that took an xt as an input to define an action
    if the SEARCH-WORDLIST fails would be a better scanner. This is simple
    to add.
    --
    Gerry

    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Gerry Jackson@[email protected] to comp.lang.forth on Tue Nov 4 23:15:37 2025
    From Newsgroup: comp.lang.forth

    On 04/11/2025 21:36, Gerry Jackson wrote:
    : iterator:  ( "name" -- xt ) \ xt of quotation
       : ]] true begin [: [[
       save-input ]] scan-words [[ restore-input
       abort" Error: RESTORE-INPUT failed"
    ;

    I just realised to my embarassment that this is unduly complicated. Of course the scanning is not required. All that is needed for iterator: is simply:

    : iterator: ( "name" -- )
    : ]] true begin [: [[
    ;

    So scan-words and the first definition of ;iterator are not needed.
    --
    Gerry
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From albert@[email protected] to comp.lang.forth on Wed Nov 5 14:21:10 2025
    From Newsgroup: comp.lang.forth

    In article <10edrl7$3v2bf$[email protected]>,
    Gerry Jackson <[email protected]> wrote:
    HunptyDumpty introduced his Y Combinator in this post: >https://groups.google.com/g/comp.lang.forth/c/ea59-OtiLvE/m/TH_8t9c7BgAJ
    with the definition
    : yc ( .. xt xt |0 -- .. ) begin while execute repeat ;

    An example from HD's post:
    : downcount dup . 1- dup 0 >= IF xt dup ELSE 0 THEN ;
    where xt is the execution token of downcount.

    Having experimented with iterators to avoid having to get the xt of a
    word I tried using a quotation:

    : foo [: <body of downcount> ;] yc ;


    I favour the { .. } notation that also replaces :NONAME .. ;

    an index is indispensable in DO , otherwise you have a
    BEGIN .. WHILE .. REPEAT so no flags.
    While we are at it:
    - limits in ascending order
    - inclusive limits
    - no unsigned bullshit

    and a DO defined like:

    lowbound upbound(inclusive) xt DO
    in the body of xt IX is the loop variable.
    LEAVE works as before.
    Experiments shows that this works in interpretation mode, thanks to
    { }

    : foo 1 10 { "we gaan naar Rome" TYPE CR } DO ;

    1 10 { "we gaan naar Rome" TYPE CR } DO

    And you can do things like
    : foo 1 10 { "we gaan naar Rome" TYPE CR } DO ;
    : DO) >R >R 0 R> 1- R> ; ( n , range [0,n) ) 1]
    : DO] >R >R 1 R> R> ; ( n , range (0,n] ) 1]

    And no unsigned indices

    FFFF,FFFF,FFFF,0000 7000,0000,000F,FFFF (empty range nothing happens)

    and no quasi infinite loops like
    0 0 DO once for index 0.

    (This I have implemented in the experimental language lucky7).

    1] mathematical notation, the upper lower limit is in the set.

    --
    Gerry

    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From albert@[email protected] to comp.lang.forth on Wed Nov 5 16:42:47 2025
    From Newsgroup: comp.lang.forth

    In article <nnd$514d5318$11208bc1@15bc1ff42b4881b6>,
    <[email protected]> wrote:
    In article <10edrl7$3v2bf$[email protected]>,
    Gerry Jackson <[email protected]> wrote:
    HunptyDumpty introduced his Y Combinator in this post: >>https://groups.google.com/g/comp.lang.forth/c/ea59-OtiLvE/m/TH_8t9c7BgAJ >>with the definition
    : yc ( .. xt xt |0 -- .. ) begin while execute repeat ;

    An example from HD's post:
    : downcount dup . 1- dup 0 >= IF xt dup ELSE 0 THEN ;
    where xt is the execution token of downcount.

    Having experimented with iterators to avoid having to get the xt of a
    word I tried using a quotation:

    : foo [: <body of downcount> ;] yc ;


    I favour the { .. } notation that also replaces :NONAME .. ;

    an index is indispensable in DO , otherwise you have a
    BEGIN .. WHILE .. REPEAT so no flags.
    While we are at it:
    - limits in ascending order
    - inclusive limits
    - no unsigned bullshit

    and a DO defined like:

    lowbound upbound(inclusive) xt DO
    in the body of xt IX is the loop variable.
    LEAVE works as before.
    Experiments shows that this works in interpretation mode, thanks to
    { }

    : foo 1 10 { "we gaan naar Rome" TYPE CR } DO ;

    1 10 { "we gaan naar Rome" TYPE CR } DO

    And you can do things like
    : foo 1 10 { "we gaan naar Rome" TYPE CR } DO ;
    : DO) >R >R 0 R> 1- R> ; ( n , range [0,n) ) 1]
    : DO] >R >R 1 R> R> ; ( n , range (0,n] ) 1]

    And no unsigned indices

    FFFF,FFFF,FFFF,0000 7000,0000,000F,FFFF (empty range nothing happens)

    Oeps. That must be
    7000,0000,000F,FFFF FFFF,FFFF,FFFF,0000 (empty range nothing happens)
    The lower limit is higher that the upper limit.


    and no quasi infinite loops like
    0 0 DO once for index 0.

    (This I have implemented in the experimental language lucky7).

    1] mathematical notation, the upper lower limit is in the set.

    --
    Gerry

    --
    The Chinese government is satisfied with its military superiority over USA. >The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --
    The Chinese government is satisfied with its military superiority over USA.
    The next 5 year plan has as primary goal to advance life expectancy
    over 80 years, like Western Europe.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Gerry Jackson@[email protected] to comp.lang.forth on Thu Nov 6 21:05:54 2025
    From Newsgroup: comp.lang.forth

    On 04/11/2025 23:15, Gerry Jackson wrote:
    On 04/11/2025 21:36, Gerry Jackson wrote:
    : iterator:  ( "name" -- xt ) \ xt of quotation
        : ]] true begin [: [[
        save-input ]] scan-words [[ restore-input
        abort" Error: RESTORE-INPUT failed"
    ;

     I just realised to my embarassment that this is unduly complicated. Of course the scanning is not required. All that is needed for iterator: is simply:


    The full code for the iterator without the redundant [IF] [ELSE] etc but including the ]] ... [[ postpone definition

    : ]] \ Single line postponer, avoids POSTPONE clutter
    begin
    >in @ parse-name s" [[" compare
    while
    >in ! postpone postpone
    repeat drop
    ; immediate

    : iterator: ( "name" -- ) : ]] true begin [: [[ ;

    : ;iterator ( -- ) ]] ;] swap while execute repeat drop ; [[ ; immediate

    \ An example
    iterator: downcount dup 0< if drop 0 exit then dup . 1- true ;iterator

    compiled as
    : downcount true begin [: dup 0< if drop 0 exit then dup . 1- true ;]
    swap while execute repeat drop ;

    cr 9 downcount \ displays 9 8 7 6 5 4 3 2 1 0

    A better example of use is a definition of a multi-line postponer.

    \ ---[ Multi-line postpone ]--------------------------

    : next postpone true postpone exit ; immediate \ could be continue
    : done postpone false postpone exit ; immediate \ could be break

    iterator: ]]
    >in @ parse-name ?dup
    if s" [[" compare
    if >in ! postpone postpone next then
    drop done
    then
    2drop refill 0= -39 and throw next
    ;iterator immediate

    \ Test
    : foo
    ]] over over + [[
    ]] >r * .
    r>

    2*
    .
    [[
    ; immediate

    : bar foo ;

    111 234 bar \ displays 25974 690

    \ ---[ Compare the gforth compatibility version ]------------

    : refilling-parse-name ( -- old->in c-addr u )
    begin
    >in @ parse-name dup 0= while
    2drop drop refill 0= -39 and throw
    repeat ;

    : ]] ( -- )
    \ switch into postpone state
    begin
    refilling-parse-name s" [[" compare while
    >in ! POSTPONE postpone
    repeat
    drop ; immediate

    \ -------------------------
    --
    Gerry
    --- Synchronet 3.21a-Linux NewsLink 1.2