2019-12-07 J Programming Language

It’s the month for Advent of Code! Perfect little programming problems, at least at first. I often try to solve some using different programming languages. I wasn’t particularly interested in solving any programming problems, but then I saw @codesections post their solutions using APL. This is the solution for day 2, apparently:

⎕IO←0
find_in←{
  ⍺←0 0
  t←⍺
  t[1]+←1
  ⍺[1]>99:⍺{t[0]+←1 ⋄ t[1]←¯1 ⋄ t find_in ⍵}⍵
  in←⍵
  in[0;1 2]←t[0 1]
  19690720=0⌷intcode in:t
  t∇in
}
intcode←{
  ⍺←0
  one←{r←,⍵ ⋄ r[⍵[⍺;3]]←r[⍵[⍺;1]]+r[⍵[⍺;2]] ⋄ (⍺+1)intcode(⍴⍵)⍴r}
  two←{r←,⍵ ⋄ r[(⍵[⍺;3])]←r[⍵[⍺;1]]×r[⍵[⍺;2]] ⋄ (⍺+1)intcode(⍴⍵)⍴r}
  1=0⌷⍵[⍺;]:⍺ one ⍵
  2=0⌷⍵[⍺;]:⍺ two ⍵
  99=0⌷⍵[⍺;]:,⍵
}
parse←{{((⌈4÷⍨⍴⍵),4)⍴⍵}⍎¨','(≠⊆⊢)⍵}
in_1←in←parse ⊃⊃⎕nget '02.input' 1
in_1[0;1 2]←12 2
pt1←0⌷intcode in_1
pt2←find_in in

It looks like it might break your brains! Apparently the key is maximal terseness. 🤯

Let me just quote this section from the Wikipedia page:

Game of Life

The following function “life”, written in Dyalog APL, takes a boolean matrix and calculates the new generation according to Conway’s Game of Life. It demonstrates the power of APL to implement a complex algorithm in very little code, but it is also very hard to follow unless one has advanced knowledge of APL.

life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}

Yes indeed...

Anyway, the lack of a special keyboard led me to the language J. The intro on Wikipedia says:

The J programming language, developed in the early 1990s by Kenneth E. Iverson and Roger Hui, is an array programming language based primarily on APL (also by Iverson).

To avoid repeating the APL special-character problem, J uses only the basic ASCII character set, resorting to the use of the dot and colon as inflections to form short words similar to digraphs.

All right! I’m going to use it to solve the day 1 problems after confirming that I know how to do it using Racket. As it turned out, the hardest part was reading a file where numbers are separated by newlines instead of spaces. Can you believe that? It took me two days to find a solution that didn’t involve splitting and joining the entire file.

The problem is that the following gives me boxed words and the newlines are also words:

;: 1!:1<'data'

The splitting and joining:

strsplit=: #@[ }.each [ (E. <;.1 ]) ,
strjoin=: #@[ }. <@[ ;@,. ]
data =. > ;: ' ' strjoin LF strsplit 1!:1 <'data'

But today I discovered:

w =. ;: 1!:1 <'data'      NB. a boxed array of words, numbers and \n
i =. 2 * i. (# w) % 2     NB. the indexes of the numbers
n =. ". > i { w    	  NB. the list of numbers, opened

I do feel bad for constructing a list of indexes, first. Surely there’s an even better way to do this. In the code above, I’m building a list of indexes. The first line results in the following:

┌──┬─┬────┬─┐
│14│ │1969│ │
└──┴─┴────┴─┘

Here’s how to understand the second and third line:

┌──┬────┐
│14│1969│
└──┴────┘

Finally! 😓

A bit later I found another way:

w =. ;: 1!:1 <'data'           NB. a boxed array of words
n =. ". > ((#w) $ 1 0) # w     NB. pick the odd ones, unbox, eval
┌──┬────┐
│14│1969│
└──┴────┘

And we’re back to where we were before. Slightly more elegant, I guess?

Anyway, the code to solve the first problem of day 1:

fuel =. verb define
 (<. y % 3) - 2
)
+/ fuel n

It really is terse. I need to use it some more. It feels like a language that forces you to think differently about the problems and I like that.

For the second day, I needed something to be called recursively. I took advantage of another feature of the J programming language: verbs can be monadic (taking one argument on the right, like fuel 14) or dyadic (taking two arguments, one on the left and one on the right). I wrote total such that calling it as total 14 was the equivalent of calling it as 0 total 14.

total =. 3 : 0
0 total y
:
f =. fuel y
if. f <= 0 do. x else. x + f total f end.
)

I feel dirty for using a conditional, haha. J is infecting my brains.

Now that I’ve written a toy program in J I wonder how anybody can write complex applications in it. Perhaps it could work. It still baffles me. To understand my inability to express my muteness in the language you have to understand that I was looking at table of contents of reference books and didn’t understand what I was looking at, didn’t know where to get the answers to my questions (such as how to remove every second cell of an array).

Here, take a look at these two pages. Apparently they are older and all the new documentation is maintained in a wiki, but still. Just staring at these pages was baffling.

On the other hand, wiki pages such as the one explaining why J has practically no loops – because all the primitives can act on arrays – makes me understand that Perl, my favorite language in all its weirdness did not come close to being as weird as this. All coding styles are possible in Perl but the culture went to object oriented programming instead of building on wantarray and making everything aware of “list context.” Too bad!

I guess if I wanted to recommend some pages to read in order, I’d say this:

  1. Nu Voc is the concise cheat sheet followed by links to essays
  2. Absolutely Essential Terms introduces you to words, nouns, verbs, ...
  3. Array Processing shows you how you should write your code
  4. Loopless explains how most loops disappear if your primitives are aware of arrays

Tags:

Comments

I am not sure if I followed it correctly, but is the list parsing working even with, for example, two newlines?

Peter Kotrčka 2019-12-10 03:28 UTC


You are right, for my code to work it is absolutely essential that there is a single newline between every number because what I’m doing is essentially picking out the odd elements.

I spent some time trying to implement a parser that just looks for digits, but failed. There’s an example of a sequential machine in their help pages, but I couldn’t get it simply emit a list of numbers.

– Alex Schroeder 2019-12-10 09:51 UTC


Please make sure you contribute only your own work, or work licensed under the GNU Free Documentation License. Note: in order to facilitate peer review and fight vandalism, we will store your IP number for a number of days. See Privacy Policy for more information. See Info for text formatting rules. You can edit the comment page if you need to fix typos. You can subscribe to new comments by email without leaving a comment.

To save this page you must answer this question:

Just say HELLO