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