bug-apl
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: APL2 Compatibility


From: Dr . Jürgen Sauermann
Subject: Re: APL2 Compatibility
Date: Sat, 28 Nov 2020 13:59:35 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0

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) 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> 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

[Prev in Thread] Current Thread [Next in Thread]