• Algol 68 - ruminations on hiding loop hierarchies in an operator

    From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Tue Apr 14 15:04:06 2026
    From Newsgroup: comp.lang.misc

    Resuming some recreational Algol 68 programming I'm working on an array-of-array (row-of-row) structure. I started as so often with
    a specific function, say,

    PROC permute_nums = (REF MAT m) VOID :
    FOR y TO 1 UPB m DO
    FOR x TO 2 UPB m DO
    REF INT where = m [y, x];
    where := num [where]
    OD
    OD;

    Since these nested loops are clumsy and are expected to appear in
    some more functions I added a generic variant

    OP ITERATE = (REF MAT m, PROC (REF INT) VOID f) VOID :
    FOR y TO 1 UPB m DO
    FOR x TO 2 UPB m DO
    REF INT where = m [y, x];
    f (where)
    OD
    OD;

    where the specific transformation function is passed as a parameter.

    Now I'm not too much concerned about performance but more about the
    clarity of the source code. It's certainly an advantage to have the loop-hierarchy only in one place. On the other hand you then either
    need a set of additional primitive transformation functions to feed
    the operator, or use ad hoc function bodies explicitly in the call of
    the generic operator; both variants degrade the overall code clarity
    again. - I wonder what people usually prefer.

    That said; a related function is printing the data. But here a simple
    'f (where)' isn't sufficient; we need newlines printed after the two
    'OD' for proper formatting. So a simple 'iterate' as depicted isn't
    sufficient anyway.

    Comments on these ruminations, thoughts and ideas, are welcome.

    Janis

    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Andy Walker@anw@cuboid.co.uk to comp.lang.misc on Fri Apr 17 15:54:33 2026
    From Newsgroup: comp.lang.misc

    On 14/04/2026 14:04, Janis Papanagnou wrote:
    Resuming some recreational Algol 68 programming I'm working on an array-of-array (row-of-row) structure. I started as so often with
    a specific function, say,
        PROC permute_nums = (REF MAT m) VOID :
            FOR y TO 1 UPB m DO
                FOR x TO 2 UPB m DO
                    REF INT where = m [y, x];
                    where := num [where]
                OD
            OD;
    Since these nested loops are clumsy and are expected to appear in
    some more functions I added a generic variant
    [code snipped -- ANW]
    where the specific transformation function is passed as a parameter.
    Now I'm not too much concerned about performance but more about the
    clarity of the source code. [...]

    Personally, I find the non-generic version clearer. ISTM that
    you're opening cans of worms with the generic version as well as making
    the code harder to understand. You yourself give the example of
    printing the array, where you need to add layout code. So you either
    have to write two generic versions, or add extra parameters to the one
    version. More generally you may want/need to add code between elements
    of the array or at the start/end of each row, complicating the generic
    version beyond reason and/or leading to the possibility of fence-post
    errors. KISS!

    Comments on these ruminations, thoughts and ideas, are welcome.
    I don't feel that four lines of code to iterate through a two- dimensional array is difficult to write or understand. If it was a 6D
    array, you might [IMO] have more reason to avoid repeating the obvious
    loops. OTOH, that might give you cause to simplify the data structures
    or take a different approach, such as pre-processing the code.

    [I once, some years ago, spent a lot of time solving puzzles
    involving tree searches (eg, for Slitherlink, Light-Up and Hashi). I
    tried to write generic code for the relevant parallel processing, but
    in the end it was (much) easier to write the specific code for one
    puzzle and copy-and-edit it for the next puzzle. YMMV.]

    Andy
    --
    Andy Walker, Nottingham.
    Andy's music pages: www.cuboid.me.uk/andy/Music
    Composer of the day: www.cuboid.me.uk/andy/Music/Composers/Sinding
    --- Synchronet 3.21f-Linux NewsLink 1.2
  • From Janis Papanagnou@janis_papanagnou+ng@hotmail.com to comp.lang.misc on Fri Apr 17 19:20:44 2026
    From Newsgroup: comp.lang.misc

    On 2026-04-17 16:54, Andy Walker wrote:
    On 14/04/2026 14:04, Janis Papanagnou wrote:
    Resuming some recreational Algol 68 programming I'm working on an
    array-of-array (row-of-row) structure. I started as so often with
    a specific function, say,
         PROC permute_nums = (REF MAT m) VOID :
             FOR y TO 1 UPB m DO
                 FOR x TO 2 UPB m DO
                     REF INT where = m [y, x];
                     where := num [where]
                 OD
             OD;
    Since these nested loops are clumsy and are expected to appear in
    some more functions I added a generic variant
       [code snipped -- ANW]
    where the specific transformation function is passed as a parameter.
    Now I'm not too much concerned about performance but more about the
    clarity of the source code. [...]

        Personally, I find the non-generic version clearer.  ISTM that you're opening cans of worms with the generic version as well as making
    the code harder to understand.

    I agree that it could lead to "opening cans of worms". (Myself I
    made good experiences with using various features of genericity.)

    I think it depends on in which way a language supports that. It
    can be very nice, or syntactically worse (like C++/STL mentioned
    below). Myself I've got late into making use of the functional
    paradigm, starting imperative, structured, data-driven, and object
    oriented, prior. Though one can write very readable code that way,
    alleviating the programmer (and readers of the programs) by much
    of the control structures spread otherwise all over the program.
    The code where this paradigm is *used* is typically very terse and
    excellent readable. (The effort or "difficulty" is then located in
    the supporting functions or framework. It's usefulness is certainly
    depending on how often you use or can re-use it in your programs.)

    But we're here discussing Algol 68. And I asked for opinions. :-)
    Hope you don't mind that I commented on the "harder to understand".

    [ identified problem with 'print'-like code snipped ]
    Comments on these ruminations, thoughts and ideas, are welcome.

        I don't feel that four lines of code to iterate through a two- dimensional array is difficult to write or understand.

    Well, if we can write complex functional OP ITERATORs an explicit
    (simple) loop-structure can hardly be "difficult to write". :-)
    That's not exactly the point. - To illustrate my thoughts...

    In languages like "C" without first-class arrays I'd write the
    loops with explicit hard coded bounds, like (easy to read)

    for (y=1; y<=N; y++)
    for (x=1; x<=N; x++)
    ...

    In Algol 68 (see quoted code above) I avoided that by using UPB,
    but in case of rows-of-rows you "want" the dimensions, and the
    simple/clean UPB results in '1 UPB m' and '2 UPB m' respectively,
    and in the context of loops reading code patterns starting like

    FOR y TO 1 ...
    FOR x TO 2 ...

    I find to be visually less clear, harder to mentally parse unless
    one adds more syntactic stuff like parenthesis (or spacing), as in

    FOR y TO (1 UPB m) DO


    Also coming from a functional-programming approach re-using code
    structures is also not uncommon (e.g. see the C++/STL library).

    Duplicating code like control-structures (usually by copy/paste)
    in each place-of-use typically impairs also code maintainability.

    If it was a 6D
    array, you might [IMO] have more reason to avoid repeating the obvious loops.  OTOH, that might give you cause to simplify the data structures
    or take a different approach, such as pre-processing the code.

    Okay. Myself I don't like [unnecessary] pre-processing and prefer
    what [sophisticated designed] languages provide. And complicating
    the process I usually - and specifically here - don't consider
    desirable. (YMMV; I know that already from another thread.)


        [I once, some years ago, spent a lot of time solving puzzles involving tree searches (eg, for Slitherlink, Light-Up and Hashi).  I
    tried to write generic code for the relevant parallel processing, but
    in the end it was (much) easier to write the specific code for one
    puzzle and copy-and-edit it for the next puzzle.  YMMV.]

    Thanks for your thoughts, comments, and preferences. Appreciated.

    Janis

    --- Synchronet 3.21f-Linux NewsLink 1.2