J Can be Readable

Functional Programming

You must be kidding me! It’s like programming using regular expressions… You’ll never make me do that again! I’m looking at the code and feel like an idiot. Isn’t it really an esoteric language like brain fuck? Does anyone really use it? And such programs can be read afterwards?

quicksort=: (($:@(<#[), (=#[), $:@(>#[)) ({~ ?@#)) ^: (1<#)

Perl is a trifle against it.

About J language

J — is a Korean of programming languages (may look confusing). It’s an explosion in reserved characters factory. Plenty of brackets, periods, slashes and it even works. It must be magic or something.

Wanting to be short or just having been carried away some people writing on J forget even simple rules of any code writing. These rules aren’t new but they acquire a critical meaning as applied to APL similar languages. As when reading ((]i.~[:{.[){([:{:[),]`([:<[$:[:>])@.([:32&=[:3!:0[:>]))«2 0 construction even a trained brain is at a loss.

I’ll show you some simple rules of readable J code.

You should not read it without going through vocabulary.

Use Mnemonics

If you don’t like using a vocabulary or just don’t feel like looking up the symbols this or that instruction is represented by, you should convert it to a verb.

head =: {.
  tail =: {:
  head 9 8 3 0 6 1 2 5 4 7
9
  tail 9 8 3 0 6 1 2 5 4 7
7

Divide and Rule

Sometimes it’s better to divide a complex construction into several simpler ones.

logistic =: dyad : '(^ - y % x) % x * *: >: ^ - y % x'

  exp =: dyad : '^ - y % x'
  logistic =: dyad : '(x exp y) % x * *: >: x exp y

Comments

J comments begin with NB., it’s exactly the case when there can’t be too much of them. If you look into standard libraries or an industrial code you’ll find hundreds of comments.

More Spaces, Different and Good Ones

An average one-liner on J consists of twenty symbols, which are weakly connected at first glance. If you locate spaces and brackets properly, they’ll help you to understand the structure of even the most complex verb.

(]%[**:@>:@])[:^[:-%~
  (] % [ * *:@>:@]) [: ^ [: - %~

Obvious is Better

For complex expressions you’d better use explicit writing instead of tacit one:

(] % [ * *:@>:@]) [: ^ [: - %~
  dyad : '(] % (x * *:@>:@])) ^ -y%x'

Hooks and Forks are Your Friends

If you didn’t know or forgot:

(f g) y ⇔ y f (g y)
  x (f g) y ⇔ x f (g y)
  (f g h) y ⇔ (f y) g (h y)
  x (f g h) y ⇔ (x f y) g (x h y)

These simple structures help to shorten the code several times, without worsening its readability.

Control Structures

There are usual control structures in J, but they can be used inside an explicit verb only.

Branchings work the same way as in any other language. If T condition returned 1, we move to B block, otherwise we move to the next else./elseif. block, if it’s there.

if. T do. B end.
if. T do. B else. B1 end.
if. T do. B elseif. T1 do. B1 elseif. T2 do. B2 end.

while. and whilst. execute B block, while T returns 1, but whilst. misses the check for the first pass, so B is always executed at least once.

while. T do. B end.
whilst. T do. B end.

for. executes B as many times as there are elements in T; for_i. creates i and i_index variables — element and its index accordingly…

for. T do. B end.
for_i. T do. B end.

select. moves to the first Ti, which has concurred with T, executing the appropriate block fcase. — case. with “falling in”.

select. T
 case. T0 do. B0
 case. T1 do. B1
 fcase.T2 do. B2
 case. T3 do. B3
end.

If B block has been executed with an error then we execute B1 block, or just ignore it. try. B catch. B1 end.

Let’s apply these rules to the following code(sudoku solver):

i =: ,((,|:)i.9 9),,./,./i.4$3
  c =: (#=[:#~.)@-.&0
  t =: [:(([:*/_9:c\])"1#])i&{+"1 1(>:i.9)*/[:i&=i.&0
  r =: [:,`$:@.(0:e.,)[:;(<@t)"1
  s =: 9 9&$@r@,

The converted code:

cells =: ,./^:2 i. 4 # 3
  rows_cols =: ((, |:) i. 9 9)
  indices =: , rows_cols, cells

  no_errors =: verb : '(-: ~.) y -. 0'

  substitutions =: verb : '(indices { y) +"1 1 ((>:i.9) */ indices = y i. 0)'
  remove_wrong =: verb : 'y #~ */"(1) _9 no_errors\"1 y'

  try =: remove_wrong @ substitutions

  solve =: verb define
    variants =: y
    whilst.
      0 e. ,variants
    do.
      variants =: ; (<@try)"1 variants
    end.
    ,variants
  )

  sudoku =: verb : '9 9 $ solve , y'
Results
m
2 0 0 3 7 0 0 0 9
0 0 9 2 0 0 0 0 7
0 0 1 0 0 4 0 0 2
0 5 0 0 0 0 8 0 0
0 0 8 0 0 0 9 0 0
0 0 6 0 0 0 0 4 0
9 0 0 1 0 0 5 0 0
8 0 0 0 0 7 6 0 0
4 0 0 0 8 9 0 0 1
   s m
2 8 4 3 7 5 1 6 9
6 3 9 2 1 8 4 5 7
5 7 1 9 6 4 3 8 2
1 5 2 4 9 6 8 7 3
3 4 8 7 5 2 9 1 6
7 9 6 8 3 1 2 4 5
9 6 7 1 4 3 5 2 8
8 1 3 5 2 7 6 9 4
4 2 5 6 8 9 7 3 1
   sudoku m
2 8 4 3 7 5 1 6 9
6 3 9 2 1 8 4 5 7
5 7 1 9 6 4 3 8 2
1 5 2 4 9 6 8 7 3
3 4 8 7 5 2 9 1 6
7 9 6 8 3 1 2 4 5
9 6 7 1 4 3 5 2 8
8 1 3 5 2 7 6 9 4
4 2 5 6 8 9 7 3 1

Now you can see what the code’s doing. It’s quite an achievement!

  • Official website
  • Wiki
  • Vocabulary — a very useful vocabulary for J study and use
  • Brief Reference
  • J for C programmers (pdf) — a textbook for those who are used to imperative programming
  • Learning J — another textbook. There are more examples in it, and each step is described in more details, than in the previous textbook
  • Puzzles — exercises
  • Phrases — useful one-liner constructions
  • Essays — articles about J, you’ll find more text, than code in it
  • Plot — building charts with the embedded tools of J

A few more:

Comments

  1. Hi Could you comment about how to handling files in J? (There is a lot of information about sintax, verbs, and so on, but precious little about files). Thanks in advance
  2. Well, when you install J, you can run the J session and either run sentence by sentence in a J execution window(ijx) or create a new script window(ijs) where the source code will go to. (File -> New ijs). Ctrl+1 to run the ijs script. But we’ll have a better article about the language itself + some more cool stuff around that topic.
  3. (⊙.⊙(☉_☉)⊙.⊙)
  4. Thanks for your answer. I meant how to read external files (estructured data) with the data to be used in a J program, and how to write the results to a file. Thanks again. By the way, that’s very good you’ll have a better article about J.
  5. Sorry for a late response. Here is a quick example:

    readfile =: 1!:1
    writefile =: 1!:2
    
    NB. Create a file and write to it
    fn =. < 'test.txt'
    'Hello Kukuruku' writefile fn
    
    NB. Read from file
    data =. readfile fn
    

    data will contain the content. But this is just a very simple example. Have you installed J?

  6. Thanks again (and yes, I’ve installed J701) One more question: For a file with a header (about 50 lines) and the rest is numeric data (maybe a thousand lines), how to read only the first 50 lines (header), or the last 950 (data) in order to process it?
  7. What do you mean by header?
  8. Header is the section of the file that contains info about structure, units, source, etc of the file. e.g. number of data columns (in data section), units of each, range of the data, associated parameters and so on. Is just an identifier like the first lines in an excel file.
  9. Using the standard «fread» verb, I’d start by partitioning the file into boxed lines using «cut»:

    lns=. <;._2 fread 'somefile.txt' The “_2” is a flag to use the last item as the partition marker and discard it from the result; the «cut» adverb “;.” boxes “<” the file into one line per box.

3,751

Ropes — Fast Strings

Most of us work with strings one way or another. There’s no way to avoid them — when writing code, you’re doomed to concatinate strings every day, split them into parts and access certain characters by index. We are used to the fact that strings are fixed-length arrays of characters, which leads to certain limitations when working with them. For instance, we cannot quickly concatenate two strings. To do this, we will at first need to allocate the required amount of memory, and then copy there the data from the concatenated strings.