πŸ’Ύ Archived View for g.mikf.pl β€Ί gemlog β€Ί 2022-03-31-apl.gmi captured on 2022-04-29 at 11:53:56. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-04-28)

➑️ Next capture (2023-04-26)

-=-=-=-=-=-=-

How I was getting started with APL recently. NARS2000.

2022-03-31

I decided to try out NARS2000. It's Windows-only but is said by the authors to work well under Wine. Although on my OpenBSD ThinkPad I don't have Wine - I only could have on the PopOS laptop.

You land in an environment that has a windows-in-window interface. Starting with the NARS2000 Session Manager.

There is a button on the toolbar to create a new function, and not much else of use.

Besides there being a keyboard of many APL characters sorted by their functionalities, with the names of their meanings showing up on the tooltip.

After creating functions, my first question was: how do i define constants for my program? It only lets me define functions!

Only then I remembered about how tutorials mentioned Immediate Execution mode that I treated as just a REPL (which it is) but not how you write programs.

So I remembered about `)VARS` command, and I knew I was supposed to just assign. In the workspace.

variable←1 2 3 4 5

The way a function definition is as a whole represented is

      βŽ•vr 'put'
    βˆ‡ result ← (where put what) board
[1]   result←board
[2]   result[βŠ‚where]←what
    βˆ‡ 2022 3 31 17 12 49 751 (UTC)

But - without the first line! The first line is the System Function VR to print the function's code. VR stands for Visual Representation. The first character is "βŽ•" (square frame character) that can be typed with Alt+L or from the characters toolbar with mouse. Its tooltip description is "Quad (βŽ•). Used as first characters in system names.".

The next first line starts with a Del (βˆ‡) (delta) and is the opening of a function definition. It starts with a name of a variable, followed by the assignment operator, followed by the declaration of function's/operator's operators with its name.

In this case that's a dyadic (i.e. two-argument) operator derived monadic (i.e. single-argument) function. There is the left operator argument "where", the right operator argument "what", and the derived function's right argument "board".

What this function does is take a value, coordinates and a matrix (a two-dimensional array, not to be confused with a "nested" array of arrays) and returns a matrix with the value "put" under the coordinates.

We have line 1 of function body (numbered) that assigns the original matrix "board" to our function result variable "result", followed by the line 2 that assigns the new value argument "what" to the coordinates "where" of "result".

In Dyalog APL, line 2 could have been

what@where⊒board

but before I was suggested to use βŠ‚where, it seemed I had to do

result[1βŠƒwhere;2βŠƒwhere]←what    ⍝ Or maybe even
result[where[1];where[2]]←what  ⍝ - which is even uglier

In the above you can see what is the character for line comments.

But what actually is that "βŠ‚where"? Note that in our case "where" is coordinates, like "(2 3)".

"βŠ‚" is called "LeftShoe" and in its monadic (single-argument) meaning it's called "Enclose".

      βŠ‚(1 2)
 1 2 
      (1 2)
1 2 
      )box on
Was OFF
      (1 2)
β”Œ2───┐
β”‚ 1 2β”‚
β””~β”€β”€β”€β”˜
      βŠ‚(1 2)
β”Œβ”€β”€β”€β”€β”€β”€β”
β”‚β”Œ2───┐│
β”‚β”‚ 1 2β”‚β”‚
β”‚β””~β”€β”€β”€β”˜2
β””βˆŠβ”€β”€β”€β”€β”€β”˜

We can see that the "enclosed" vector has its outer box labelled with an epsilon. That suggests a set of one element!

That would mean the square-brackets index syntax accepts either semicolon-demilited coordinates, or a *set* of coordinates

Let's try union operator on it then (a down shoe):

      (βŠ‚(1 2))βˆͺ(βŠ‚(2 3))
β”Œ2────────────┐
β”‚β”Œ2───┐ β”Œ2───┐│
β”‚β”‚ 1 2β”‚ β”‚ 2 3β”‚β”‚
β”‚β””~β”€β”€β”€β”˜ β””~β”€β”€β”€β”˜2
β””βˆŠβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
      (1 2)βˆͺ(2 3)
β”Œ3─────┐
β”‚ 1 2 3β”‚
β””~β”€β”€β”€β”€β”€β”˜

Boxes labeled with a tilde on the bottom represent vectors, label on top indicates size of the "box".

Well, I lied to you with the epilons being sets.

http://wiki.nars2000.org/index.php/Multisets

Part of the reason the so-called set functions in APL are in an odd state is that they are defined on sets, but implemented on non-sets.

The epsilon on the bottom of a box only means it is a nested vector, i.e. containing other vectors.

And it turns out there are counterparts of the set operations in APL that use the Multiset Operator modifier and they always preserve the *multiplicity* of an element in the collections (vectors, basically).

If left shoe is called Enclose, and right shoe is called Disclose, then what will happen if we try to "disclose" the vector of two vectors, which was union of two enclosed vectors?

      βŠƒ((βŠ‚(1 2))βˆͺ(βŠ‚(2 3)))
β”Œ2───┐
2 1 2β”‚
β”‚ 2 3β”‚
β””~β”€β”€β”€β”˜
      

It made us a matrix where our original vectors are now rows!

But let's want a function that would do "zipping" of two vectors for us, i.e. giving us pairs of nth elements from each of the vectors.

A shorter way to declare a function, one that makes it anonymous (unnamed), is to place a single expression in curly braces. Optionally maybe we can add more of them, separating with the Diamond (β‹„) character, described as "Used as statement separator". In case of anonymous function/operator syntax, we can use Omega (⍡) (small omega) symbol to recall the right argument.

We can just assign it to a name and that will be equivalent to a full-fledged function definition.

      )box off
Was ON
      zip←{⍉↑⍡}
      zip (1 2 3) (4 5 6)
1 2 3

That's not what we want, but a Stack Overflow answer told us this would work! But the

NARS2000 wiki article "Implementation Comparisons"

tells us

Dyalog's definition of the monadic function ↑ [up arrow] depends upon the value of βŽ•ML [system variable ML] (βŽ•ML<2 is Mix, βŽ•MLβ‰₯2 is First), whereas NARS2000 uses the monadic function βŠƒ [right shoe] for Mix and ↑ [up arrow] for First

ML is said to stand for "Migration Language".

We try and

      zip←{β‰βŠƒβ΅}
      zip (1 2 3) (4 5 6)
1 4
2 5
3 6

This time it returned us a matrix of three rows and two columns, with the columns being our original arrays, therefore the rows being our desired zipped pairs. Note that this time without boxes - because we disabled boxes with a system command earlier. These boxes are toggled with system command "box" accepting arguments "on" and "off". System commands start with a right parenthese.

How does it work though? The "circle slope" character monadic meaning is "Reverse All Coords" even though its dyadic meaning is "Transpose", but it can be said that it does a transposition, whatever the actual "Transpose" meaning does with its additional left argument. And when you try using right shoe ("Disclose") on two arrays (naturally for APL, that usually amounts to an array of two arrays as usually you don't need additional parentheses around them for that) it returns you a matrix of which the two vectors are rows.

And the "up arrow" function called "First" in this langauge "migration" or variant? It was getting the first of the two arrays and then giving it to the transpose (or "Reverse All Coords" if you wish), which did nothing.

But I wanted a ("nested") vector of vectors-pairs and not a matrix of rows-pairs. So I was searchengining. And under one stackoverflow answer two comments stood out for me:

https://stackoverflow.com/questions/17688146/apl-matrix-manipulation-trick#comment25799947_17699818

Monadic down arrow is known as "split" and does the same thing as βŠ‚[2] [left shoe with square-bracketed 2], converting a matrix into a vector of vectors. May not be available in all APL implementions. – Paul Mansour, on Jul 17, 2013 at 15:56
@PaulMansour - That's probably the case since I'm using NARS2000. I'll try it with βŠ‚[2] [left shoe with square-bracketed 2]. Thanks for the response. – Expedito, on Jul 17, 2013 at 16:03
      βŠ‚[2]β‰βŠƒ(1 1 2 3)(4 4 5 6)
β”Œ4──────────────────────────┐
β”‚β”Œ2───┐ β”Œ2───┐ β”Œ2───┐ β”Œ2───┐│
β”‚β”‚ 1 4β”‚ β”‚ 1 4β”‚ β”‚ 2 5β”‚ β”‚ 3 6β”‚β”‚
β”‚β””~β”€β”€β”€β”˜ β””~β”€β”€β”€β”˜ β””~β”€β”€β”€β”˜ β””~β”€β”€β”€β”˜2
β””βˆŠβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Now that we came back to nested vectors, I am thinking that that the number on the right may possibly mean the level of nesting. I am too lazy right now to write expression to test that and then caption all the boxes ascii art with extensive title text, though.

Next let's mention "⍴" ("Rho") operator. In its monadic form it's called Shape because it returns the shape. In its dyadic form it's called Reshape because it creates a vector from the given elements.

      ⍴(6 24 ⍴ 0 1 2 3)
β”Œ2────┐
β”‚ 6 24β”‚
β””~β”€β”€β”€β”€β”˜
      6 24 ⍴ 0 1 2 3
β”Œ24──────────────────────────────────────────────┐
6 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3β”‚
β”‚ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3β”‚
β”‚ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3β”‚
β”‚ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3β”‚
β”‚ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3β”‚
β”‚ 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3 0 1 2 3β”‚
β””~β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Let's look at another thing

      2/{βˆ… ⍡}Β¨2 βˆ… 4
β”Œ6────────────────────────────────────────┐
β”‚β”Œ2───┐ β”Œ2───┐ β”Œ2───┐ β”Œ2───┐ β”Œ2───┐ β”Œ2───┐│
β”‚β”‚ βˆ… 2β”‚ β”‚ βˆ… 2β”‚ β”‚ βˆ… βˆ…β”‚ β”‚ βˆ… βˆ…β”‚ β”‚ βˆ… 4β”‚ β”‚ βˆ… 4β”‚β”‚
β”‚β””+β”€β”€β”€β”˜ β””+β”€β”€β”€β”˜ β””~β”€β”€β”€β”˜ β””~β”€β”€β”€β”˜ β””+β”€β”€β”€β”˜ β””+β”€β”€β”€β”˜2
β””βˆŠβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Since the crossed circle symbol means float (floating point number) NaN (Not a Number), it is different type from an integer. Therefore, vectors containing both are of some kind of mixed type that has plus on their boxes in place of a tilde.

Let's deconstruct the expression. From right to left: 2 NaN 4 is a vector; the upper two dots ("Dieresis") is described as "Each operator" - here it takes a function and a vector; the function is just one that returns an array of a NaN followed by the argument to it; that goes into a Slash ("Replicate" operation) with left argument two. The result is that for each of 2, NaN, and 4, an array of NaN and the element is made, and then of the resulting array each inner vector is repeated 2 times.

Ok but commands

Sometimes a function may not want to save (into the workspace, not to disk) because "that would damage the SI".

http://wiki.nars2000.org/index.php?title=System_Command_SI

Those are just interruptions that you want to ignore unless you're debugging, you can safely clean them with )SIC command.

I'm done, I'm tired, I want this pushed to the site. It is as it is. Hope you enjoyed.

There are many amazing thing about NARS2000 that I haven't covered. They may come next.

I wonder if you see how every code block in this post has an extensive alt-text.