# array theory question

## John Nowak — 2008-12-22 23:32:11

    I know some of your here are familiar with APL, Nail, etc, so I

    thought I'd ask.

    My question is this: Am I correct in thinking that single element

    arrays in Nial (and I believe also APL2) are equivalent to their

    contents? In other words, does {42} == 42? Also, does anyone know

    anything about the history of this question as it pertains to APL?

    Thanks in advance.

    The rest of this email is confusing, but I left it in anyway. It may

    help explain why I'm interested in the question of {x} == x.

    - - -

    The reason I ask is that this has implications for the "constructive"

    language I recently mentioned. There seem to be five ways of passing N

    arguments to a function:

    1. Use curried functions (not an option here)

    2. Pass tuples when N > 1 (what I proposed previously, but has

    limitations)

    3. Pass null-terminated lists when N > 1 (the approach of FP)

    4. Pass null-terminated lists (stacks) in all cases (the concatenative

    approach)

    5. Pass arrays in the style of Trenchard More's array theory (as in

    Nial, possibly APL2)

    The first option (currying) is out because there's just no way I can

    see to combine such an approach with pointfree programming without

    making it horribly painful (like it is in Haskell).

    The second approach (tuples) seems to have annoying limitations,

    although its simplicity is appealing.

    The third approach (lists) is nicer than using tuples but it is still

    impossible to write a generic function that does partial application.

    The reason is that when partially applying to a function that takes

    two values, you need the resulting function to enlist the second

    argument passed to it before consing on the first. If the function

    takes three values however, you do not need to enlist because a list

    is already being passed in and you can just cons on the partially

    applied value and then apply as normal. I hope that makes sense...

    The fourth approach is out because it makes the form of "construction"

    useless: If everything takes and returns a stack, then using

    construction will always result in a stack of stacks. For example,

    '[sq, sq] 5' would return '[[25][25]]'. Getting at the values

    afterwards is a huge pain.

    The fifth approach has the benefits of the third but also allows

    partial application. If we decide that {x} == x, then we can have

    generic partial application because it will "automatically" enlist the

    object passed to the function resulting from the partial application

    if necessary. This sort of auto-enlisting also makes it much easier to

    generalize scalar operations to arrays (i.e. we can view a function

    like 'square' as one that operates on all elements of an array, but

    since the single element array is the same as the element it contains,

    we can also pass it scalar values).

## John Nowak — 2008-12-23 00:16:43

    On Dec 22, 2008, at 6:32 PM, John Nowak wrote:

     > My question is this: Am I correct in thinking that single element

    > arrays in Nial (and I believe also APL2) are equivalent to their

    > contents? In other words, does {42} == 42?

     Actually, I think my question should've be more precise: Do single

    element arrays *containing atoms* equal the atoms that they contain?

    I did manage Nial running. I somehow missed the binaries on the site

    before. It does indeed turn out that '42 = {42}' as I had understood

    from the array theory paper (http://www.nial.com/Documents.html).

    However, it is not the case that '{{1 2}} = {1 2}'.

    I think this is exactly the behavior I need. All functions could take

    and return a single array, but construction (I guess called "atlas" in

    Nial) would still work nicely (e.g. '+ [1, 2]' == '[3]' == '3'). I

    suppose I'm reinventing something.

    I think I've answered my question, but if anyone has thoughts on

    Nial's approach to arrays as opposed to, say, APL's or J's, I would

    very much appreciate them.

    - John

## John Cowan — 2008-12-23 00:18:45

    John Nowak scripsit:

     > My question is this: Am I correct in thinking that single element

    > arrays in Nial (and I believe also APL2) are equivalent to their

    > contents? In other words, does {42} == 42? Also, does anyone know

    > anything about the history of this question as it pertains to APL?

    > Thanks in advance.

     The answer to the question, as posed, is "No".  But a better question

    is this: "Is a scalar an array"?  And the answer to that is "Yes, a

    scalar is an array of rank 0, which by definition contains 1 element."

    This is true AFAIK in all APL-derived languages.  A single-element array

    can be of any rank.

    Backing off to your underlying issue, there is no problem with either

    identifying tuples of size 1 with scalars in languages that have tuples,

    or not doing so.  ML, Haskell, and Pure do: Python and Q don't.

    --

    Work hard,                                      John Cowan

    play hard,                                      cowan@...

    die young,                                      http://www.ccil.org/~cowan

    rot quickly.

## John Cowan — 2008-12-23 00:21:03

    Scripsi:

     > The answer to the question, as posed, is "No".  But a better question

    > is this: "Is a scalar an array"?  And the answer to that is "Yes, a

    > scalar is an array of rank 0, which by definition contains 1 element."

    > This is true AFAIK in all APL-derived languages.

     Except, as it turns out, Q'Nial version 6 (the current version) which

    no longer implements array theory exactly, according to Wikipedia.

    --

    Not to perambulate                 John Cowan <cowan@...>

        the corridors                  http://www.ccil.org/~cowan

    during the hours of repose

        in the boots of ascension.       --Sign in Austrian ski-resort hotel

## John Nowak — 2008-12-23 00:47:50

    On Dec 22, 2008, at 7:18 PM, John Cowan wrote:

     > Backing off to your underlying issue, there is no problem with either

    > identifying tuples of size 1 with scalars in languages that have

    > tuples,

    > or not doing so.  ML, Haskell, and Pure do: Python and Q don't.

     You are correct here. The issue is that I want to do it with lists/

    arrays of arbitrary length, not tuples. In other words, I'd like this

    to work, where '&' is a psuedo partial application and ':' is

    application:

        (add2 & 2) : 3       ==>  5

        (add3 & 2) : {3, 4}  ==>  9

    The question here is what the semantics of '&' are. In the former, it

    appears to be as such where '++' is 'cons':

        (f & x) : y  ==  f : (x ++ (y ++ {}))

    In the latter however, the enlisting of the argument on the right side

    of the application is not necessary as it is already a list:

        (f & x) : {y, z}  ==  f : (x ++ {y, z})

    What I'm hoping might make sense here is making the atom 'y'

    equivalent to '{y}'. This would allow the second form of '&' shown

    above to be used in the general case. Do you think that may be

    workable? Is it comparable to what Nial or APL do?

    Thanks for the help.

    - John

## John Cowan — 2008-12-23 01:56:51

    John Nowak scripsit:

     > What I'm hoping might make sense here is making the atom 'y'

    > equivalent to '{y}'. This would allow the second form of '&' shown

    > above to be used in the general case. Do you think that may be

    > workable? Is it comparable to what Nial or APL do?

     Ah^2.  What you want is Algol 68's "rowing coercion" ("row" being A68

    jargon for vector, or 1-D array).  This coercion transforms a non-row

    value into the corresponding row value with one element.  It's applicable

    only where the type is uniquely known at compile time: in A68 jargon,

    in the following "strong contexts":

    o	the actual parameters of a function call

    o	a type cast

    o	the RHS of an assignment, contant declaration, or variable

    	declaration with an initializer

    o	the body of a procedure (which is an expression in A68)

    o	all the arms of an if- or case-expression except one

    o	either side, but not both, of an identity expression

    It's interesting note that A68, as of the Revised Report, has two kinds

    of 2-D arrays:  "row row of <whatever>", which is a C-style rectangular

    matrix, and "row of row of <whatever>", which is a Java-style vector of

    pointers to vectors.  (These are the names of the types, not the way you

    write them in declarations.)  Consequently, there are four kinds of 3-D

    arrays, and in general 2^(k-1) kinds of rank-k arrays.

    --

    MEET US AT POINT ORANGE AT MIDNIGHT BRING YOUR DUCK OR PREPARE TO FACE WUGGUMS

    John Cowan      cowan@...      http://www.ccil.org/~cowan

## John Nowak — 2008-12-23 02:27:11

    On Dec 22, 2008, at 8:56 PM, John Cowan wrote:

     > John Nowak scripsit:

    >

    >> What I'm hoping might make sense here is making the atom 'y'

    >> equivalent to '{y}'. This would allow the second form of '&' shown

    >> above to be used in the general case. Do you think that may be

    >> workable? Is it comparable to what Nial or APL do?

    >

    > Ah^2.  What you want is Algol 68's "rowing coercion" ("row" being A68

    > jargon for vector, or 1-D array).  This coercion transforms a non-row

    > value into the corresponding row value with one element.

     Very interesting! I suppose the question I'd need to answer is if it's

    sufficient to only go from scalar -> vector. I think the answer is

    "no" if functions like 'square' are meant to operate on vectors rather

    than scalars as then 'square 5' would return a one element vector and

    I'd be back to the same problem regarding construction. It would be

    sufficient however for functions like 'sum' that always return a

    scalar but can consume either a scalar or vector as input. For things

    like 'square', there's always map.

    The choices I make here are going to end up depending on the

    complexity of the necessary type system more than anything else. It's

    quite likely that I won't be able to offer a map-like operation that

    works on the vector passed to a function. This is essentially the same

    state of things in a language like Factor where there's no way of

    applying a function to every element of the stack (without using with-

    datastack and then replacing the main stack or something awful).

    Instead, you have stack and arrays as separate concepts. If I go this

    route, the rowing coercion will be sufficient. The only place I think

    I really need to use it is for partial application anyway. It seems a

    shame though to need to add this notion to the type system just for

    this one case, although perhaps there's a nice way of working it into

    the notation so it seems obvious.

    Thanks again.

    - John

## Stevan Apter — 2008-12-23 13:14:40

    this was a hot topic in the 70s, during which time several

    vendors proposed different extensions to the APL\360 type

    system.  in boxed or grounded array systems, enclosure of an

    atom (a "simple scalar" of depth 0) has depth 1.  in nested

    or floating or ungrounded array systems, enclosure of an

    atom is a no op.  Sharp APL and J are boxed systems, IBM's

    APL2 and STSC's Nested Arrays are floating systems.

    the most immediate effect of grounded vs. ungrounded systems

    is that in the latter, but not the former, a simple scalar

    can be an element of a nested array.  e.g. where <x is the

    enclosure of x

        (<1 2 3;4)

    is possible in APL2, but not in Sharp APL, which requires

        (<1 2 3;<4)

    K is grounded, but strictly speaking has lists and not arrays.

    K can have

        (1 2 3;4)

    also see trenchard more's work on array theory:

    http://domino.research.ibm.com/tchjr/journalindex.nsf/0/415fa6b9fe085ed785256bfa0068419d?OpenDocument

     ----- Original Message -----

    From: "John Nowak" <john@...>

    To: "concatenative" <concatenative@yahoogroups.com>

    Sent: Monday, December 22, 2008 6:32 PM

    Subject: [stack] array theory question

    >I know some of your here are familiar with APL, Nail, etc, so I

    > thought I'd ask.

    >

    > My question is this: Am I correct in thinking that single element

    > arrays in Nial (and I believe also APL2) are equivalent to their

    > contents? In other words, does {42} == 42? Also, does anyone know

    > anything about the history of this question as it pertains to APL?

    > Thanks in advance.

    >

    > The rest of this email is confusing, but I left it in anyway. It may

    > help explain why I'm interested in the question of {x} == x.

    >

    > - - -

    >

    > The reason I ask is that this has implications for the "constructive"

    > language I recently mentioned. There seem to be five ways of passing N

    > arguments to a function:

    >

    > 1. Use curried functions (not an option here)

    > 2. Pass tuples when N > 1 (what I proposed previously, but has

    > limitations)

    > 3. Pass null-terminated lists when N > 1 (the approach of FP)

    > 4. Pass null-terminated lists (stacks) in all cases (the concatenative

    > approach)

    > 5. Pass arrays in the style of Trenchard More's array theory (as in

    > Nial, possibly APL2)

    >

    > The first option (currying) is out because there's just no way I can

    > see to combine such an approach with pointfree programming without

    > making it horribly painful (like it is in Haskell).

    >

    > The second approach (tuples) seems to have annoying limitations,

    > although its simplicity is appealing.

    >

    > The third approach (lists) is nicer than using tuples but it is still

    > impossible to write a generic function that does partial application.

    > The reason is that when partially applying to a function that takes

    > two values, you need the resulting function to enlist the second

    > argument passed to it before consing on the first. If the function

    > takes three values however, you do not need to enlist because a list

    > is already being passed in and you can just cons on the partially

    > applied value and then apply as normal. I hope that makes sense...

    >

    > The fourth approach is out because it makes the form of "construction"

    > useless: If everything takes and returns a stack, then using

    > construction will always result in a stack of stacks. For example,

    > '[sq, sq] 5' would return '[[25][25]]'. Getting at the values

    > afterwards is a huge pain.

    >

    > The fifth approach has the benefits of the third but also allows

    > partial application. If we decide that {x} == x, then we can have

    > generic partial application because it will "automatically" enlist the

    > object passed to the function resulting from the partial application

    > if necessary. This sort of auto-enlisting also makes it much easier to

    > generalize scalar operations to arrays (i.e. we can view a function

    > like 'square' as one that operates on all elements of an array, but

    > since the single element array is the same as the element it contains,

    > we can also pass it scalar values).

    >

## John Cowan — 2009-01-05 02:25:10

    John Nowak scripsit:

     > > Ah^2.  What you want is Algol 68's "rowing coercion" ("row" being A68

    > > jargon for vector, or 1-D array).  This coercion transforms a non-row

    > > value into the corresponding row value with one element.

    >

    > Very interesting! I suppose the question I'd need to answer is if it's

    > sufficient to only go from scalar -> vector. I think the answer is

    > "no" if functions like 'square' are meant to operate on vectors rather

    > than scalars as then 'square 5' would return a one element vector and

    > I'd be back to the same problem regarding construction.

     Right.  However, rowing can be applied more than once.  Note that in

    Algol 68, rowing is not done to the arguments of operators, so that

    vector + scalar and matrix + scalar can do the right thing rather

    than rowing the scalar and probably throwing an array conformity error

    at compile time.

    --

    All Norstrilians knew what laughter was:        John Cowan

    it was "pleasurable corrigible malfunction".    cowan@...

            --Cordwainer Smith, Norstrilia