[net.lang.apl] Nested arrays

kwh@bentley.UUCP (KW Heuer) (05/19/86)

In article <371@water.UUCP> water!ljdickey (Lee Dickey) writes:
>GCOS APL allows things of the sort  list  <-  (a;b;c)
>[In IBM's APL2] one uses "strand notation" ...  list2  <-  a b c

Neither of these notations allows you to write a zero- or one-element list.
(I know, you can't directly write a zero- or one-element vector either*.)
You can get around that by changing the notation to "{a;b;c}".  But this
still seems inelegant.

>[Sharp APL has] new primitives called enclose and disclose.  The result of
>enclose is always a scalar.  Disclose is a left inverse of enclose.

I find this one easiest to understand.  Enclose always returns a scalar of
(new) type "tree"; arrays are still homogeneous but the scalars in a tree
array may disclose to any object; the "standard scalar" of type tree (the
filler value for overtake or expand, corresponding to numeric zero and
character blank) is the enclosure of an empty tree.  This is the "grounded"
tree model.

There's also a "floating" tree model, whose main distinction is that for any
scalar foo, foo equals enclose foo.  (In the grounded model, "0" "<0" "<<0"
(monadic "<" is enclose) are all distinct objects, and ">0" gives a domain
error.)  I think this causes unnecessary complications -- you have to allow
true heterogeneous arrays, and I think the "first" element is distinguished.

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint
*I lied.  '' denotes a zero-element character vector.  What you can't write
is a numeric vector of length zero or one, or a character vector of length
one, as a constant.  Or any array of higher rank.  Are 2D lists permitted in
GCOS APL or APL2?  Does "2 2 rho {a;b;c;d}" work?

ljdickey@water.UUCP (Lee Dickey) (05/22/86)

Question:
> ... Are 2D lists permitted in
>	(1) GCOS APL or
>	(2) APL2?  
> Does "2 2 rho {a;b;c;d}" work?

Answer:
	(1) No.
	(2) I dunno.  Does anybody else ?

moews_2@h-sc2.UUCP (moews_2) (05/23/86)

In article <834@bentley.UUCP> kwh@bentley.UUCP (KW Heuer) writes:
>...
>
>I find this one easiest to understand.  Enclose always returns a scalar of
>(new) type "tree"; arrays are still homogeneous but the scalars in a tree
>array may disclose to any object; the "standard scalar" of type tree (the
>filler value for overtake or expand, corresponding to numeric zero and
>character blank) is the enclosure of an empty tree.  This is the "grounded"
>tree model....
>
>Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint

   Uh, but what exactly is the "empty tree"?  If we define

   <scalar> ::= <number> | <character> | enclose(<array>)

   <array> ::= n-dimensional array of (<scalar>)'s, n >= 0

then there IS no empty tree --- every enclosure has an array inside it.  If
you want a "default" scalar of type tree, I think you'd be better off
reintroducing ONE object x0 satisfying x0 = >x0, and letting that be the
default value.   (Is this perhaps what you meant?)
--
David Moews        moews@h-sc4.harvard.EDU     ...!seismo!harvard!h-sc4

kwh@bentley.UUCP (KW Heuer) (05/27/86)

In article <957@h-sc2.UUCP> h-sc2!moews_2 writes:
>In article <834@bentley.UUCP> kwh@bentley.UUCP (KW Heuer) writes:
>>I find this one easiest to understand.  Enclose always returns a scalar of
>>(new) type "tree"; arrays are still homogeneous but the scalars in a tree
>>array may disclose to any object; the "standard scalar" of type tree (the
>>filler value for overtake or expand, corresponding to numeric zero and
>>character blank) is the enclosure of an empty tree.  This is the "grounded"
>>tree model....
>
>   Uh, but what exactly is the "empty tree"?  If we define
>   <scalar> ::= <number> | <character> | enclose(<array>)
>   <array> ::= n-dimensional array of (<scalar>)'s, n >= 0
>then there IS no empty tree --- every enclosure has an array inside it.

By "empty tree" I meant "zero-length vector of type tree."  The "standard
tree scalar" is  ENCLOSE 0 RHO ENCLOSE anything.  Sorry about the confusion.

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint

blickstein@dregs.dec.com (06/01/86)

I think some of the most significant features of nested arrays have been
overlooked in the discussion here.

Most of the discussion has centered on how nested arrays give you more
flexible data representation.   The examples pretty much amount to how
you can use nested arrays in ways similar to records and structures in
the various "FORGOL" (my term for procedural languages that are descendents
on FORTRAN (Pascal, Ada, C, etc.)).  

While this kind of usage is unquestionably a tremendous benefit to APL users, I
think one of the principle motivations behind them was to be able to apply
operators and functions more flexibly. It's not very exciting to be able to
represent data more naturally unless you are also given the means to operate on
it more naturally as well. 

For example, in regular APL, operators are limited to scalar functions
(functions that operator on one (monadic) or two (dyadic) scalars to
produce a third scalar.  Why this limitation?  Well obviously without
nested arrays operator usages like 3 o. rho 4 5 6 would be undefined.
(RESULT[1] would have to be 3 rho 4 (a vector), but the shape of RESULT[1]
is by definition a scalar?)   Nested arrays give this example a meaningful
definition:  (4 4 4) (5 5 5) (6 6 6).   This is a three element vector
where each element is a nested 3 element vector.   rho RESULT[1] is '',
but rho disclose RESULT[1] is 3.

So clearly operators can now be generalized to accept practically any
function because it no longer matters that the function returns something
other than a scalar.

There's a lot you get right there, but what the most important benefit
is when you realize that it now becomes meaningful to apply operators
to USER DEFINED functions.  This removes the need for most loops in
APL.   It also allows you to write shorter AND CLEARER programs because
you can now use APL primitives where you couldn't before.  For example, if 
you write a function PAYROLL that processes one employee record (presumably in 
an array EMPLOYEES) in current APL you'd probably have to write a loop 
that makes a call to PAYROLL at each iteration i to process EMPLOYEE[I;].

That is you are applying PAYROLL to each row in EMPLOYEE, a very APL-ish
thing to do, but you have to do it in a loop.   In nested arrays this
could be done simply with each employee.  (Each is a new operator available
on most nested array implemetations that applies a function to each element
(or slice) of an array).

This is obviously a clearer program than the one with the loop because
it's a DIRECT notation for what you are doing (applying PAYROLL to each
EMPLOYEE), whereas it might take a little mental processing to figure
out the loop that does the same thing.

Because the use of operators is FAR less restricted with nested arrays,
you see a lot of new operator-related enhancements in most nested array 
implementations including:

	1) New operators like each.
	2) Derived functions.  That is "3 +" is a "derived" monadic function
           that adds 3 to its argument.  (It is often useful to compose a
           derived function to be passed as an operand to an operator.)
	3) User-defined operators (on some systems).

If I had to give a summary description of what nested arrays buys you, it
would be something like: APL works most naturally on arrays and nested arrays
allow you to treat more things directly as arrays.

	Dave Blickstein

(UUCP)  {allegra|decvax|ihnp4|ucbvax}!decwrl!dec-rhea!dec-tle!blickstein

(ARPA)  BLICKSTEIN%TLE.DEC@DECWRL.ARPA