Hi Jürgen,

thank your for the ≡≡ (deep depth:-) of your explanation and covering the boundaries of this wonderful language. 45 years ago I learned, that working with APL there was never ever a side effect caused by a "more sensible syntax short cut" for the sake of readability. Made me scratch my head one time or the other, but with your help and support those worries are from the past:-)

Best Regards
Hans-Peter



Am 28.11.20 um 13:59 schrieb Dr. Jürgen Sauermann:
Hi Hans-Peter,

this kind of surprises has puzzled me since the early days of APL.
They already existed in APL1 but never occurred in practice since
the number of constructs affected, for instance +//'ABC'  was small
and did not make much sense at that time.

The proliferation of operators in APL2 then not only increased the
number of affected constructs but also included constructs that could
make sense. Your examples are instances of these constructs.

In C/C++ the order in which functions/operators are evaluated is
unambiguously defined by two attributes of each operator: its precedence
and its associativity. The precedence defines in which order different groups of operators (like × or ÷ versus + or -) are computed while the associativity defines the order (like left-to-right or right-to-left) in which operators with
the same precedence are computed.

In APL, however, the situation is rather different. The ISO standard indirectly specifies the well-known right-to-left evaluation of APL expressions, but does
not specify an order when it comes to APL functions versus APL operators.
Hybrids like /, ⌿, \, and ⍀ make matters even worse. IBM APL2 is more specific
about that by essentially defining that:

(1) /, ⌿, \, and ⍀ are (monadic) operators (even though their (single) left argument could
    be a value), and

(2) arguments of operators bind stronger than arguments of functions.

(3) the left operand of an operator can be a value or  a function,

Although these rules determine the order of evaluation in most cases they do not, at least as I understand the matter, catch all cases. The missing piece is how two handle the pattern A O P B where A and B are values and O and P are monadic operators (of which O allows a value as left argument). This pattern has two
valid evaluations:

(A O) P B and A (O P) B

The first evaluation binds A to O, the derived function (A O) is then bound to P, giving another derived function ((A O) P) which is then evaluated with argument B.

The second evaluation binds O to P, and the derived function (O P) is then
evaluated with arguments A and B.

As already mentioned this this can only occur if an operator allows a value as left argument, which is fortunately only the case for a few pathological operators,
(in particular /, ⌿, \, and ⍀).

I have tried to explain this in earlier versions of the GNU info manual, but have removed it recently due to a somewhat incorrect and misleading wording in the manual.

With the above explanation in mind, I believe that GNU APL behaves correctly even though a different behaviour (with unfortunately different resuilts) would be equally correct.

You can, BTW,  watch the GNU parser at work by enabling logging facility 32 (note that the program counter PC of the virtual APL machine counts from right to left).

*      ]LOG 32

      1 2 3 / ¨ 'ABC'**
**
**changed to Prefix[si=2]) ============================================**
**    [si=2 PC=0] Read token[0] (←0←) VALUE1«≡⊏3⊐ABC» TC_VALUE**
**fifo[si=2 len=1 PC=1] is now : TC_VALUE  at Prefix.cc:564**
**    [si=2 PC=1] Read token[1] (←0←) ¨ TC_OPER1**
**fifo[si=2 len=2 PC=2] is now : TC_OPER1 TC_VALUE  at Prefix.cc:564**
**    [si=2 PC=2] Read token[2] (←0←) / TC_OPER1**
**fifo[si=2 len=3 PC=3] is now : TC_OPER1 TC_OPER1 TC_VALUE  at Prefix.cc:564**
**   phrase #297: M M matches, prio 42, calling reduce_M_M__()**
**   reduce_M_M__() returned: RA_CONTINUE**
**fifo[si=2 len=2 PC=3] is now : TC_FUN12 TC_VALUE  at Prefix.cc:564**
**    [si=2 PC=3] Read token[2] (←0←) VALUE3«≡⊏3⊐1 2 3» TC_VALUE**
**fifo[si=2 len=3 PC=4] is now : TC_VALUE TC_FUN12 TC_VALUE  at Prefix.cc:564**
**   phrase #234: A F B matches, prio 33, calling reduce_A_F_B_()**
**   reduce_A_F_B_() returned: RA_CONTINUE**
**fifo[si=2 len=1 PC=4] is now : TC_VALUE  at Prefix.cc:564**
**    [si=2 PC=4] Read token[1] (←0←) ENDL TC_END**
**fifo[si=2 len=2 PC=5] is now : TC_END TC_VALUE at Prefix.cc:564**
**   phrase #46: END B matches, prio 2, calling reduce_END_B__()**
** A BB CCC **
**   reduce_END_B__() returned: RA_PUSH_NEXT**
**    [si=2 PC=5] Read token[0] (←0←) RETURN_STATS TC_RETURN**
**fifo[si=2 len=1 PC=6] is now : TC_RETURN  at Prefix.cc:564**
**   phrase #13: RETC matches, prio 1, calling reduce_RETC___()**
**- end of ◊ context**
**   reduce_RETC___() returned: RA_RETURN**
**Prefix::reduce_statements(si=2) returned VOID in StateIndicator::run()**
**      1 2 3 / ¨ 'ABC'**
*
Finally, if you need GNU APL to behave differently, then you can
enforce a different order by means of { and }, similar to ( and ) for
values.

The default behaviour of GNU APL is this:
*
**       1 2 3 /¨ 'ABC'**   ⍝  / bound to ¨
** A BB CCC *

which corresponds to pattern A (O P) B above. If you prefer (A O) P B instead,
then you can do this:

*      {1 2 3/⍵} ¨ 'ABC'   ⍝ 1 2 3 bound to /**
** AAAAAA BBBBBB CCCCCC

*which corresponds to pattern (A O) P B above. This is almost as easy as
using parentheses for values.

Best Regards,
Jürgen



On 11/26/20 1:28 PM, Hans-Peter Sorge wrote:
Hi,

I thought so, APL is fun:-)

The following 4 expressions are just a repeat:
⍝1 - a vector replicates a scalar. The result is a simple vector
     1 2 3/'A'
AAAAAA

⍝2 - scalar by scalar - simple vector as result
      1 2 3/'ABC'
ABBCCC

⍝3 - as in ⍝1 but  for each scalar  a vector replicates a scalar. The result is a nested vector of simple vectors
      (⊂1 2 3)/¨'ABC'
 AAAAAA BBBBBB CCCCCC

⍝4 - is consistent with ⍝2  the each-operator introduces one level of depth
      1 2 3/¨'ABC'
 A BB CCC

The next result would be "surprising" to me as it is somewhere between 2 and 3 and logic asside, "feels" inconsistent:
⍝4
⍝      1 2 3/¨'ABC'
⍝ AAAAAA BBBBBB CCCCCC


Going a little further. The simple vector 'ABC' is being turned into a nested vector.
⍝5,6
      1 2 3/,¨'ABC'
 A B B C C C
      1 2 3/∊¨'ABC'
 A B B C C C

⍝9 - scalar applied to simple vector
      2/'ABC'
AABBCC
      2/¨'ABC'
 AA BB CC

⍝ 10  -  as expected having a nested vector:
       2/,¨'ABC'
 A A B B C C

Here comes my irritation. Or some missing knowledge ....
⍝ 11 - if this is true ( from ⍝3 )
     (⊂1 2 3)/¨'ABC'
 AAAAAA BBBBBB CCCCCC

⍝ 12 - then this schould be different
      (⊂1 2 3)/¨,¨'ABC'
 AAAAAA BBBBBB CCCCCC
⍝ expected
A AA AAA  B BB BBB  C CC CCC


⍝ 13 - instead of domain error ..
      (⊂1 2 3)/'ABC'
DOMAIN ERROR
      (⊂1 2 3)/'ABC'
      ^       ^
⍝ the result could be
AAAAAABBBBBBCCCCCC

⍝ 14 - like in case of a simple vector, the nested vector results are accordingly:
      1 2 3/'AA' 'BB' 'CC'
 AA BB BB CC CC CC

⍝like ⍝4
       1 2 3/¨'AA' 'BB' 'CC'
 AA BBBB CCCCCC

⍝ 15 - and , analogous to 12
      (⊂1 2 3)/¨'AA' 'BB' 'CC'
LENGTH ERROR
      (⊂1 2 3)/¨'AA' 'BB' 'CC'
      ^        ^
⍝ could then be
AA  AA AA  AA AA AA   BB  BB BB  BB BB BB   CC  CC CC  CC CC CC

Just my thoughts..

Best Regards
Hans-Peter


Am 24.11.20 um 17:17 schrieb Dr. Jürgen Sauermann:
Hi Adam,

thanks, see below.

Best Regards,
Jürgen


On 11/23/20 11:07 PM, Adám Brudzewsky wrote:

For the sake of compatibility with IBM APL2

Speaking of which, what is GNU APL's official policy?

GNU APL's general policy regarding standards and the like is to consider,
(in that order):

1. the IBM APL2 language reference manual,
2. the IBM APL2 implementation (PC demo version, can't aford the commercial version),
3. the ISO standard,
4. other APL implementations and suggestions from bug-apl@gnu.org.

Sometimes, however, this can have undesirable consequences and then
some sort of common sense is applied to change the order.

I noticed that the info manual (https://www.gnu.org/software/apl/apl.html#APL-symbols-that-can-be-functions-or-operators <https://www.gnu.org/software/apl/apl.html#APL-symbols-that-can-be-functions-or-operators>) is factually wrong about APL2, claiming that:

    the ambiguity related to / ⌿ \ and ⍀ is not resolved by these
    rules.

I see. That statement is probably a left-over from the early days of GNU APL. When I started with GNU APL, all I had was some vague recollection of APL1 from the 1970s (my first APL computer was an IBM 5110 desktop, a precursor of the IBM PC). At that time functions were functions and values were values. At some later time, triggered by the ⍤-operator (which was not implemented in IBM APL2 but defined in ISO), I changed to the APL2 way of handling /
and \.

I have updated the documentation, *SVN 1363*.
The APL2 language reference does in fact make it perfectly clear how / and friends are treated, namely as operators. Always. Note:

    image.png

And then:

    image.png

Note that this makes APL2 ISO non-compliant. Indeed, here, GNU APL follows Dyalog and NARS2000:
      1 2 3/¨'ABC'
 A BB CCC

While APL2 and APLX give:
      1 2 3/¨'ABC'
 AAAAAA BBBBBB CCCCCC
This is because 1 2 3/ is a derived monadic function and ¨ maps the entire function to each letter.

I believe older GNU APL versions would have given the APL2/APL X results, while newer versions give the other result. This is one of the examples where the general GNU APL policy is not being followed. If an incompatibility with APL2 exists long enough with no complaints from the users, then I believe backward compatibility with GNU APL is more important than compatibility with IBM
APL2.

On Mon, Nov 23, 2020 at 9:21 PM Dr. Jürgen Sauermann <mail@jürgen-sauermann.de <mailto:mail@j%C3%BCrgen-sauermann.de>> wrote:

    Hi Kacper, Adam,

    thanks. For the sake of compatibility with IBM APL2 I have
    changed *⎕UCS* so that
    it accepts float and complex numbers that are near to
    integers.  My initial thinking was
    that e.g.*⎕UCS* of a complex number is most likely a
    programming mistake so
    that a DOMAIN ERROR would be more helpful than being a burden.
    But APL2
    compatibility is an even stronger argument in this case.

    I have also adjusted the integer domain which is now -$80 ...
    $7FFFFFFF
    so that no conflicts with signed bytes from *⎕FIO *should arise.

    *SVN 1362*.

    Best Regards,
    Jürgen



    On 11/22/20 11:11 PM, Kacper Gutowski wrote:
    On Sun, Nov 22, 2020 at 03:19:19PM +0100, Dr. Jürgen Sauermann
    wrote:
    Floating point and complex numbers are not allowed as to
    avoid interference with ⎕CT (i.e. how should rounding be
    performed?).

    I share your sentiment regarding the upper bound of the ⎕UCS
    domain, but throwing a domain error on ⎕UCS1E2 looks like a
    bug to me too.  1E2 is clearly an integer regardless of the
    implementation details, and I would be surprised if APL2
    didn't accept it.  I would expect rounding to be the same as
    in all the other places that require near-integers, like array
    indices.

    The negative ones are also a bit weird.  I wasn't aware of
    their existence, and they seem to work in surprising ways when
    passed to various variants of ⎕CR.

    -k





Reply via email to