User:Ian Clark/JinaDay

From J Wiki
Jump to navigation Jump to search

J in a Day

You are someone who knows APL, but little or no J. You're unable to put off learning J any longer. But you don't wish to know how far in advance of old-fashioned APL it is, how much better, slicker, terser, more consistent and logical. Not to say cheaper and more portable. You'll judge that for yourself, thank-you, once you know a bit more about it.

People tell you J isn't just APL without the funny symbols. Your knowledge of APL, they say, is no use to you, so forget it and start from scratch. But you can't find a month to learn a whole new language, simply to do differently what you can do perfectly well already. And so another year goes by...

This article is for you. Put aside this evening (though you'll be up late) -- and see if you can take on-board enough J to make learning it a self-sustaining process. If the day ends and you've got nowhere, well... at least you tried.

J can be downloaded free-of-charge. Not just a 30-day trial version: the full monty. Yours to keep.

Go to http://www.jsoftware.com/stable.htm (which we shall write as: {22mvx2n}) and get it working on your computer. Type-in 2+2 and press Enter (or Return). Once you can achieve this, read on...

   2+2
4

What you've just typed-into is the IJX window, which is "kinda like" the APL session.

Let's use ~~ in comments to mean "kinda like", as in: NB. IJX ~~ APL Session

For economy's sake, I'm going to be saying things that "ain't necessarily so". They're factoids to get you started.

By the time you find out exactly how they "ain't so", you'll know enough to take it in your stride.

Information.png Latest edition: -- Ian Clark <<DateTime(2010-11-29T01:56:21Z)>>

A note to J experts

This article is a trial draft of an eventual VECTOR submission. It isn't really for you, unless you can accurately recall your state-of-mind as an APL-er meeting J for the first time. A year into J -- and I'm beginning to forget, myself.

The approach is idiosyncratic, and maybe just plain wrong in places. I've reinvented the wheel a lot: not a better wheel, but a more familiar one (to me). But if you can spot where the wiki contains a better treatment of a topic, I'd really appreciate you emailing me with the tip.

I've used TinyURLs systematically an an experiment in concise efficient in-line references. Thus, this article is {33ta68u}. See full list at the bottom. Tell me if I've missed off a must-have.

J for the APL Programmer {34agevb} is essential reading, but IMO doesn't meet the goal this article sets itself. The J Primer {22wvtqv} is the best I've seen in the J documentation on the web for a beginner. It's more thorough than my fast-track treatment, which cuts corners mercilessly. But it doesn't leverage an APL-er's existing knowledge. It's an act of faith on my part that this is worth doing.
-- Ian Clark <<DateTime(2010-10-24T06:49:22Z)>>

This article contains APL characters

Don't know APL? You can still get a lot from this article, but allusions to APL primitives will of course go straight over your head. But in that case it won't matter if APL primitives are showing correctly or not. Just read on...

But if you do know APL, then the stuff about APL will be useful. But if the primitives have been munged by the browser, it will cause you some avoidable head-scratching. So let's check that you're viewing them correctly...

←↑→↓∆∇∊∘∧∨∩∪∼≡≢≤≥⊂⊃⊖⊢⊣⊤⊥⋄⌈⌊⌶⌷⌹⌽⌿⍀⍉⍋⍎⍒⍕⍝⍞⍪⍳⍴⍵⍷⍺⎕○×÷

The above code-section should look like this (snapshotted on a Macintosh):

Aplsnapshot.jpg

If that's not what you see, then take a look at Typesetting/APL Fonts for advice on how to proceed.

The JFE (J front-end)

You happen to be using the JFE (J-front-end).

The JFE is itself programmed in J. That code is accessible to you, and you can modify it.

You may think you don't need to know that at this stage. Wrong. The JFE is a superb source of sample code for programming a serviceable gui. It's a treasure-chest of utilities. If the JFE needs to do it then, sooner or later, you'll need to do it.

We'll see how to look at the code of the JFE later.

The IJX window

You are typing into the IJX window (IJX for short). You only have one of them, and if you make it go away then J stops. You can save it as a txtfile (having the extension .ijx) but don't tinker just yet: it's best left as it comes.

But suppose you did choose menu File > Save at his point, you'd save a txtfile: 1.ijx in the folder:

(Win2000:) "C:\Documents and Settings\Administrator\j602-user\temp\1.ijx"

(Mac:) "/Users/myname/j602-user/temp/1.ijx"

(Platform-portable:) "~user/temp/1.ijx"

...and J is fairly tolerant about you using either \ or / in paths.

But you're wise not to mix 'em.

The IJX behaves more like a text editor than a typical APL session manager. You can re-enter lines (...any lines: your past input and J's responses) but IJX acts differently from what you're used to.

Enter 2+2 if you've not done so already. The IJX looks like this:

   2+2
4

Click at the end of 2+2 and type +1. Now press Enter.

It does not re-execute!

What happens is that the line is brought down for you to optionally overtype before re-entering.

The result is a redundant line... and a mutilated record of your session.

So get into the habit of click-entering the line you want to re-input -- and then edit it.

The source code window (IJS)

Select menu: File > New ijs (Ctrl+N)

A new empty window appears. This is the IJS window.

Correction: it is an IJS window -- you can have several of them.

You can make the IJS window go away without J terminating. JFE will invite you to save the contents as a txtfile (having extension: .ijs).

The IJS (and its associated txtfile) is the main way to develop a collection of code -- indeed a whole application.

IJX ~~ APL Session
IJS ~~ edit window
IJS ~~ saved APL workspace

...this is metalanguage; not real J code!

You'll be meeting a lot of 3-letter acronyms with "J" in them. Stick a sheet of paper on the wall and start noting them down.

As a beginner you'll want to re-enter expressions in lots of different ways, plus keeping memorable instances in some sort of recoverable form.

There's a better way of doing it than re-entering past lines from IJX. Consider this way:

  NB. recipe book of sample input statements
QQ=: ''''                                                NB.01
QQ=: '"'                                                 NB.02
zu=: dtb {.zux=: >zub=: 'alpha' ; 'bravo' ; 'charlie'    NB.03
zub ; zux ; zu                                           NB.04
zu ; zux ; zub                                           NB.05
qt=: 3 : 'QQ,(":y),QQ'   NB. explicit form               NB.06
qt=: 13 : 'QQ,(":y),QQ'  NB. tempt into tacit form       NB.07
qt=: QQ , QQ ,~ ]        NB. tacit form (as input)       NB.08
qt=: '''' , '''' ,~ ]    NB. tacit form (resolved)       NB.09
qt                                                       NB.10
qt f.                                                    NB.11
qt zu                                                    NB.12
qt zux  NB. fn(string) naturally generalises to array    NB.13
qt"1 zux   NB. use Rank (") to get it how you want       NB.14
'Here is a message in the form of a string.'             NB.15
smoutput '...and here is another message.'               NB.16
smoutput 60$'_'                                          NB.17

The trailing NB.01 to NB.17 have no function except to number the lines.

Paste the above code sample into an empty IJS window.

You should be looking at one already. If you haven't, then select menu: File > New ijs

Input the entire window to IJX. Select menu: Run > Window

This acts as if you had typed it all by hand into IJX.

Note: it doesn't echo IJX output whilst loading, not even computed values, except for those lines preceded by smoutput.

If you want J to echo everything to IJX whilst it's reading the IJS window, then select: Run > Window Display
You might want to do this if there's bad code in the IJS -- it's easier to see where, because loading will stop with an error message.

Input only a selection. Eg: select lines 4 and 5, and then select menu: Run > Selection

This is good not only for running blocks of lines, but also sub-expressions within a single line.

Input a single line. Eg: click on line 4, and then select menu: Run > Line

You can run lines repeatedly, and in different orders, copying interesting variants into your IJS.

Memorise the hotkeys to perform these 3 tasks quickly without thinking.

They're all together on a QWERTY keyboard: Ctrl+W, Ctrl+E, Ctrl+R.

Keep this IJS window open.

Or save it into your ~user folder as recipebook.ijs, and get it back at a future date by: File > Recent.

We will be using it again in what follows.

Distributing programs and applications

When it comes to distributing an application (app for short) on a given platform (*.exe in M$ Windows, *.app in MacOS) then J, like APL, needs special measures. It's not difficult: it's mainly a process of gathering all the code libraries needed and gelling them into some packaged form. Many programmers go though their entire careers never bothering to do it. They just keep folders of source code files and run them as needed.

You can do that in J also.

As with modern scripting language (eg JavaScript) you keep your J source code in txtfiles which you can create and edit using Notepad (Win) or TextEdit (MacOS). (If only in principle.)

Edit them using File > Open User....

If you find you can't alter the window, toggle the read-only setting: Edit > Read Only

Save the result, File > Save (Ctrl+S) and run the open IJS window Run > Window (Ctrl+W).

Or run them straight from a saved file, Run > File.

Do this repeatedly: the (re-)defined functions and variables simply get overwritten with their new definitions.

Generating a trivial GUI app to get you started

Writing a GUI application might seem like learning to run before you can walk. But once you know your way around the system, learning J syntax and features is easy because you can speedily and confidently experiment. That's why it's worth getting familiar with the basic tasks of creating, saving, editing and debugging scripts, before you even start looking at J in any great depth.

Let's generate a trivial GUI application using the Form Editor.

Get a fresh, empty IJS: File > New ijs
Make sure it is the window selected, then...
Select menu: Edit > Form Editor...

A dialog window asks you for Form Id and Form Type.

Specify Form Id: calc --and Form Type: baseform.ijs.

A WYSIWYG work-window appears: calc, also a palette: Design -- calc.

(Beneath the palette, your new IJS window gets populated with code.)

At this point you can create buttons and other controls, but don't bother yet. Just click OK.

Your new IJS gets updated with the result of your interactions with the Form Editor to form this script:

CALC=: 0 : 0
pc calc;
menupop "File";
menu new "&New" "" "" "";
menu open "&Open" "" "" "";
menusep;
menu exit "&Exit" "" "" "";
menupopz;
xywh 136 8 44 12;cc ok button;cn "OK";
xywh 136 23 44 12;cc cancel button;cn "Cancel";
pas 6 6;pcenter;
rem form end;
)

calc_run=: 3 : 0
wd CALC
NB. initialize form here
wd 'pshow;'
)

calc_close=: 3 : 0
wd'pclose'
)

calc_cancel_button=: 3 : 0
calc_close''
)

This defines a noun and three verbs:

CALC
calc_run
calc_close
calc_cancel_button

Run the IJS: Run > Window

Nothing appears to happen.

The noun and verbs get defined (and you can see them in the IJX if you enter their names) -- but they don't get run.

You'll need to execute calc_run somehow.

Add one more line at the bottom of the IJS:

calc_run''

and run the IJS: Run > Window

The trivial GUI window: calc appears, and you can interact with it.

(You could instead have entered calc_run'' into the IJX. Click Cancel and try it...)

Note(1): calc_run needs a right argument, even if no use is made of it (in this case '', although you could use 0).

There is no such thing as a niladic function in J: all verbs must be given a right argument (whether or not any use is made of it), even though an (optional) left argument can be omitted.

Note(2): the cursor has got to be winking in the IJS, or the menu item is grayed-out.

Interact with the app's GUI.

The Cancel button works, but the OK button does nothing (as yet).

It needs a handler to execute some J code when the button is pressed.

Try this, inserting it just above the line: calc_run''

n=: 0

calc_ok_button=: 3 : 0
smoutput 'Hello World' ; n=:n+1
)

This shows incidentally how to get output for debugging purposes from an explicit definition whilst it's running -- or from the IJS whilst it's loading -- viz use: smoutput (standing for session-manager output).

The syntax for a handler name is always: <formID>_<controlID>_<controltype>.
In this case:

<formID>:        calc
<controlID>:     ok
<controltype>:   button

Cancel the CALC window, re-run the IJS and click OK.

Hello World, boxed, plus a running count, appears in IJX each time you click OK.

If you smoutput just the simple string, like this:

smoutput 'Hello World'

then the box does not appear and you just see Hello World.

It's the use of (;) that causes the box.

Unboxed arrays in J, unlike APL, cannot mix chars and numbers. Boxed arrays can.

Or you can convert numbers to strings like this (but (;) is more convenient and docile in use):

smoutput 'Hello World ', ": n=:n+1   NB. ": ~~ ⍕

Now it often happens that you want different controls to run the same verb. In this demo, calc_cancel_button and calc_close are two such verbs. It is quite okay to assign one to the other, or to assign a third verb having a name like terminate to each of them. Following straight after the definition of noun CALC, you'll see that this has in fact been done:

calc_cancel_button=: calc_close

...No y, no dummy arguments, nothing.

A simple, yet non-trivial, application

As installed, J comes with demo applications, eg: File > Open System... > open: examples / demo / coins

But they're all rather complicated, loading library files stored elsewhere.

Here is a simple application with everything contained in one single IJS. But not too simple: it actually has its own GUI, plus some meaningful code. When you run it, a classic calculator appears in its own window.

The script was originally generated by the Form Editor and touched-up to add features and functionality. You'll recognise the definitions of CALC, calc_run and calc_close, although these have been altered, for reasons to be discussed.

Wm yes check.png

Type the following into IJX:

   jpath '~user'

This shows the full path to your J user folder for miscellaneous scripts. Download the above script: calc.ijs and move it into that folder.

Now open it in an IJS window:

   open '~user/calc.ijs'

Don't try to make sense of it just yet. Just make sure you can open it and read the contents.

Now execute it: Run > Window (Ctrl+W)

Explanation of the J source code for CALC

We've written CALC in a special way, to introduce J code neatly and compare it with APL. Let's work down the sample in the IJS.

The script consists of a number of explicit definitions, each of which is an assignment: =:

Comments in J code

NB. -starts a comment, which finishes at the end of the line.

To add / remove NB. from a block of lines of code: Tools > Selection > ...

Defining a text array for global use

The line:

CALC=: 0 : 0

--starts defining a noun called: CALC. A single right-paren causes the definition to terminate:

)

Everything in-between (including linefeeds!) becomes the contents of noun: CALC. It specifies the form layout: the buttons and edit field of the demo calculator. That should be fairly obvious.

You never need to write the contents of CALC yourself. Let the Form Editor do it for you. If you select the IJS window and choose: Edit > Form Editor it will find where you've defined CALC and enable you to redefine it.

But let's just take a brief look at a given line of CALC:

xywh 5  20 18 18;cc num7 button;cn "7";

It reads, in effect: "At xy-position (5 20 18 18); create a child control [cc] having id num7 which is a button; having caption [cn] 7".

But as far as the J system is concerned, CALC is nothing but a character-vector... a string. It has embedded linefeeds (LF) which split it into several lines on output to IJX.

Examine the noun CALC which calc.ijs has defined for you in J. Enter into IJX:

   $CALC       NB. $ ~~ ⍴
659
   LF e. CALC  NB. e. ~~ ∊
1
   LF-: 10{a.  NB. ~~ ⎕TCLF≡ 10⊃⎕AV ...and J is ALWAYS ~~ ⎕IO=0
1
   +/LF=CALC   NB. counts the linefeeds in CALC
18
               NB. which equals the number of rows displayed.

LF is actually a noun defined in system script: stdlib.ijs.

Recall that we first used the Form Editor to create a starter version of CALC. That version had stubs for a crude File menu (which isn't hard to see how to expand into what you want). But our CALC demo doesn't employ menus, so we've deleted the stubs.

Syntax sugar (verb define)

In passing, let's look at the J words verb and define:

   verb
3
   define
:0
   type'define'
+------+
│adverb|
+------+

These J words are "built-in", to the extent they are loaded at the start of a J session, provided your installation is a standard one. They are defined in a library script: ~system/main/stdlib.ijs. They enable you to write verb definitions like this:

calc_close=: verb define
wd'pclose'
)

instead of like this:

calc_close=: 3 : 0
wd'pclose'
)

which, as a beginner, you might find more readable and informative.

Besides verb (=3), and its alias monad, there are other predefined buzzwords you should know about:

  noun           0
  adverb         1
  conjunction    2
  verb           3
  monad          3
  dyad           4

The script stdlib.ijs sets them up with a single assignment, like this:

'noun adverb conjunction verb monad dyad'=: 0 1 2 3 3 4

Note how to assign several words in one statement, or to split a vector into separate nouns for each element.

So let's summarise like this:

NB.  ~~  ⍝
noun ~~  (global) variable
verb ~~  function
word ~~  variable, function, or operator
z=:  ~~  z←
foo=: verb define  ~~  ∇foo ...∇
foo=: verb define  ~~  ⎕FX'...'

Handlers: closing the app's main form

When the close box on the app's form is clicked, a handler is invoked whose name has got to be <formID>_close. This becomes calc_close here.

You can't have a different name. But such a verb need not exist, in which case nothing happens.

The verb calc_close is an example of a handler. Another example is: calc_num9_button, which is invoked when the digit button "9" (having id: num9) is clicked.

All handlers have this in common: they are monadic verbs which ignore their argument(s).

Recall us saying that there is no such thing in J as a niladic verb.

Verbs which you'd expect to be niladic in APL are monadic in J, and must be called with a right argument, even though it is disregarded.

We said this in connection with calc_run above.

By convention, the dummy argument used to call them with is '' (the empty string), or sometimes it is 0.

Handlers fall into this category. The gui invokes them when a control is clicked.

You rarely actually write code to call them yourself, except to make different controls run the same block of code.

Any monadic verb can be assigned to a handler, in order to make it do work when its control is clicked. This includes expressions which evaluate to a monadic verb. We'll see examples of this soon. The verb thus assigned to a handler will always be invoked (by the gui) with no left argument, and a right argument having as its value the empty string.

The Form Editor, as we saw earlier, generated for us a simple version of the verb: calc_close to close the app's form. Unfortunately it's too simple. Here it is again:

calc_close=: 3 : 0
wd'pclose'
)

Each time you re-run IJS, surplus dead forms are left open, if you neglect to close them first.

The new script calc.ijs has a better calc_close which doesn't fail when there's no form present:

calc_close=: verb define
wd :: 0: 'psel calc; pclose;'  NB. failsafe version
)

You don't need to know how calc_close works right now. When you feel confident using the J Vocabulary (Voc for short) {5up9gw} you can go and look up the primitive: Adverse (::) {32nhxyb}.

So now calc_run can safely call calc_close'' before creating a new form, to get rid of any existing form. But it won't fail if there's no such form yet.

You can assign some surprising things to each other

Verbs, like nouns, can be assigned to names. So also can adverbs and conjunctions. This is the simplest instance of tacit definition, viz definition which is "taciturn" where its arguments are concerned.

Note: there are 4 kinds of entity in J to which you can assign a name:

0   noun
1   adverb
2   conjunction
3   verb

First-generation APL only lets you assign arrays, and combine them in expressions.

Array, let us recall, is a term which includes scalars as well as vectors and matrices.

It is used in J as well as APL.

Dyalog APL lets you assign so-called functions and operators too, and combine them in simple expressions under Compose (). For example:

   myfn←f∘g  ⍝ ~~ [J] myfn=: f@g

J extends the possibilities enormously, allowing just about every primitive to take part in expressions to combine verbs, adverbs and conjunctions. Subject to rules, of course.

The rules governing this sort of expression-building are called tacit programming.

A simple monadic verb: format

See the block of code:

NB. =========================================================
format=: format1		NB. CHOOSE DESIRED DEFN FROM...
format1=: ":			NB. equivalent to primitive: (":)
   ...
NB. =========================================================

It's a rough-and-ready "development kit" for experimenting with different ways of defining the verb format. This is called by verb update which updates the calculator's display register.

There's a pre-defined selection of verbs: format1, format2, etc. One of them (viz format1 here) is assigned to: format. It is easy to switch to another alternative, say format4, by entering in IJX:

   format=: format4

There is also a test tool: ftt whose sole purpose is to apply a trial number (y) to each verb in turn whose name begins with "format". You can add further format*-definitions at any stage, and ftt will automatically include them.

A collection of ftt statements (which you can add-to) is offered for re-execution using Run > Line. Notice how they reside in the script to get ignored when the script loads:

0 : 0	NB. Execute these using Ctrl+R ...
ftt 99999999	NB. fills classic 8-digit display
ftt 999999999	NB. 9 digits
ftt 9999999999	NB. 10 digits, crosses 31-bit threshold
   ...
)

The phrase 0 : 0, equivalent to noun define, collects the ensuing statements, down to the right-parenthesis, into a definition, but fails to assign it to a name or output it to the IJX session via smoutput. So it is discarded.

If you actually want it output to the J session, then precede it with smoutput like this:

smoutput 0 : 0   NB. Execute these using Ctrl+R ...
   ...
)

Let's consider the format*-verbs in turn.

Verb format1 is evidently an alias for the built-in primitive: (":). It can be used interchangeably with (":) in J code of any kind.

Verb format2 does the same as format1, but it does it differently.

format2=: monad define		NB. converts J numeral syntax
": y				NB. Just use the primitive (":)
)

It is an explicit definition, showing how its argument y is acted on by the primitive (":) and the resulting string returned. Verb format1 is an example of a tacit definition, though of the simplest.

In APL we'd define format2 in an analogous way:

∇z←format2 y
z←⍕y
∇

But J has no need of the header: ∇z←format2 y

In J, the left argument is always x and the right argument is always y. And there is always a value returned and it is always the last value calculated (whether or not it is assigned to a local or global noun).

There is an obscure exception: the last value calculated in a so-called T-block lying between controls if. and do. in an if.-statement.

So there is no need for: z=: or z=. corresponding to APL: z← to return a value.

Yes, there is a control-word: return. --which exits the definition, returning the value of the preceding expression {3xn3tm9}.

But you don't often need it.

It appears in the script of calc.ijs, but only to disable the test-verb trace.

So in this case we need only specify an (unassigned) expression: ": y -- and that's what gets evaluated and returned when format2 is run.

Verb format3 is constructed just like format2 but uses a so-called foreign (!:) verb instead, also called Format (8!:2).

The preceding Ravel (,) is needed because (8!:2) returns a Rank 2 (2-dimensional) array, even for a single number.

Foreigns are comparable to APL's quad- (or system-) functions and variables. They provide I/O, number formatting and conversion and platform-specific services. See {3yhbsfa}.

Verb format03 is a single-line explicit definition equivalent to format3.

format03=:  3 : ',(8!:2)y'	NB. identical to format3
format13=: 13 : ',(8!:2)y'	NB. gives same result here as format4
format4=: [: , 8!:2		NB. tacit definition

What follows 3 : is quite evidently a string. You can construct or provide this string any way you like, eg from substrings strung-together using Append (,).

Note that format3 gets optimised into a form identical to that of format03, as you will see if you type format3 into IJX.

A genuinely multiline verb like equals doesn't do that.

Nor does one containing NB.-comments.

Verb format4 is a tacit definition, functionally equivalent to format3.

We shall have more to say about tacit code later. Let's just note here that you can ask J to convert an explicit to a tacit definition by replacing the 3 (=verb) with 13, as shown in the definition of format13 here. If J can't convert it to tacit form it returns the same definition you gave it. In this case it can convert it, hence format13 and format4 are identical

as you can verify by typing their names into IJX.

Verb format5 is a multi-line explicit definition. Its only purpose here is to demonstrate how J mimics certain familiar coding tasks in APL.

format5=: monad define		NB. crude fix for eg: _1e10
y=. ": y
if. 'e' e. y do. y=. ,'0' end.	NB. zero anything in sci format
'-' (I. y='_') }y		NB. convert J Negative sign
)

It improves on the simple use of (":), which converts a number to J syntax, including denoting a negative number by (_).

Firstly it detects the character 'e' in the numeral. Since this usually means (but alas not always) a very small number which ought to be displayed as '0', this line simply replaces the numeral under construction (currently residing in y) with ,'0'.

Lastly it replaces all instances of (_) with (-). This phrase:

'-' (I. y='_') }y     NB ~~ y[(y='_')/⍳⍴y]←'-'

is an instance of:

a=: n i } a           NB. ~~ a[i]←n

where i is here a vector of the indexes (I.) of 1's in y='_', these being the characters to be replaced by (n:) '-'.

This construct is exhibited in {34mhmlw} as the J counterpart of APL's indexed assignment.

There is no indexed assignment in J. It refuses to assign just part of a, hence a itself must be assigned the result of replacing only the element i in a. Here, there is no need to assign the result back to y, since it is the value to be returned.

Verb format6 is an improved version of format5.

format6=: monad define		NB. zero numerals like: 1e_10
y=. ,(8!:2)y			NB. replace (":) by Format (8!:2)
if. +./'e-' E. y do.		NB. detect 'e-' in eg: 1e-10
  y=. ,'0'
end.
NB. --last calculated value is returned
NB. --which just so happens to be an assignment to: y
)

Use of (8!:2) in place of (":) automatically converts (_) to (-). And the line detecting scientific notation in format5 is refined to detect only negative powers of 10, using (E. ~~ ⍷) instead of (e. ~~ ∊).

Finally, Verb format7 shows how to define an ambivalent verb, ie one taking an optional x-argument:

format7=: verb define		NB. How to code an ambivalent verb
,(8!:2)y	NB. monadic: format7 y
:
,x(8!:2)y	NB. dyadic: x format7 y
)

We shall say more about this below.

Re-defining a J word using IJX

Notice that if you type the bare name of a verb (or other word) into IJX, J outputs its current definition, which is its "value". But the form this definition takes is something that you can alter.

Type: format3 into IJX.

Do you get it showing like this?

   format3
+-+-+----+
|3|:|": y|
+-+-+----+

Or like this?

   format2
┌─┬─┬────┐
│3│:│": y│
└─┴─┴────┘

If so, enter the following, then try again:

   (9!:3) 5   NB. "Linear" form of definition.
   format3
3 : '": y'

To get "Boxed" form back again, enter: (9!:3) 2

You could also have done this by chosing Edit > Configure... --then: Category [Display]; Display Form [check boxes].

We prefer "Linear" format in this article, because re-entering it (overtyped) will redefine the word. Line-by-line if a multi-line definition -- and not forgetting the closing ). But a beginner may prefer "Parens" or "Boxed", because this splits a tacit definition up into easier-to-understand chunks.

How to offer a parameter to a handler

The verb: digit appends a digit to the display whenever a button "0" to "9" is pressed. Here is how it is defined:

digit=: monad define
d=. {. ":y
if. NEWNUMBER do. result=: '' [ NEWNUMBER=: 0 end.
put result,d
)

Notice that digit makes mention inside its code of the right argument: y. It expects y to be the integer value of some digit, 0, 1, 2, ..., 9.

But digit cannot be a handler, or assigned as it stands to a handler, such as calc_num9_button, because, as we've already said, handlers disregard their argument(s).

How, then, do we use it as a handler? Answer: we use a predefined verb: bind to pass the argument 9 (say) to verb digit, like this:

calc_num9_button=: digit bind 9

The J word bind isn't a verb or a noun, it's a conjunction. It "conjoins" two words to form a verb, which is monadic. The verb so produced happens to ignore its argument(s). So it's good for assigning to a handler, such as calc_num9_button.

   type'bind'
+-----------+
|conjunction|
+-----------+
   zz=: digit bind 9
   type'zz'
+----+
|verb|
+----+
   zz''
NB. ...appends '9' to the display, just as if the "9"-button was pressed.

digit bind 9 is an example of an expression which computes, not a noun, but a verb.

Localising a word in J

Notice that digit has a local noun: d, which gets assigned the char digit: '0' -- '9' corresponding to the integer argument: y.

digit=: monad define
d=. {. ":y
if. NEWNUMBER do. result=: '' [ NEWNUMBER=: 0 end.
put result,d
)

In APL we would maybe define digit like this:

∇digit y;d
d←↑⍕x
:If NEWNUMBER ⋄ result←'' ⋄ NEWNUMBER←0 ⋄ :End
put result,d
∇

...but the J verb doesn't have a header. So how do we ensure that d is localised? Simply by using =. in place of =:.

Thus we see from the J definition of digit that result and NEWNUMBER are both globals (they are always assigned using =:) but d becomes localised just by virtue of using =..

If d is already present as a global word, its value after d=. ... is masked until digit exits.

Warning: you cannot mix d=. and d=: in the same definition. Alas, J doesn't warn you, in so many words. Put it on your list of things to check-for, in case your code misbehaves and you can't see why.

Warning: d never becomes "semi-global", as it can in APL. You can't see its value inside the definition of any verb called by digit. What you'll see is the global value of d, if there is one.

When entering expressions directly into IJX, either =. or =: can be used and the effect is the same.

This is convenient when re-executing lines from a verb listing in IJX.

By assigning y and x sample values, you can simulate the execution of a given verb line-by-line, without using the debugger.

Warning: the noun result is used also by the gui, to echo the contents of the eponymous edit field.

This is why we don't need an actual statement to fetch result from the form: the gui updates it automatically for us.

Conditional statements in J, all on one line

Yet another thing to notice about digit is the syntax of a conditional statement {36xlq4t}. Also the way J contrives to fit two logically distinct statements on the same line, without having a "diamond" separator ().

Note that x [ y returns the value: x. But y needs to be evaluated in order to do that.

Warning: don't assume ([) behaves exactly like ().

For one thing, APL evaluates expression1 ⋄ expression2 in the order: expression1 then: expression2,

but J evaluates expression1 [ expression2 in the order: expression2 then: expression1.

For another thing, J "looks ahead" when extracting tokens to evaluate from a train,

so there are occasionally strange effects, words not being updated in the order you expect.

If that happens, try: expression1 [[ expression2

Writing an ambivalent verb

A verb which can run with or without its x-argument is called ambivalent. Often you want such a verb to run different sections of its code depending on whether x is present or not. A special instance of this is to run the verb recursively to provide a default x-argument.

You don't have to test for the presence of x. J can be asked to do that for you.

Here's how to define a variant of format to run separate sections of code for monadic or dyadic invocation:

This is an "instrumented" form of the format7 appearing in calc.ijs.

format7=: verb define
smoutput 'monadic y=' ; y
,(8!:2)y	NB. monadic: format7 y
:
smoutput 'dyadic x=' ; x ; 'y=' ; y
,x(8!:2)y	NB. dyadic: x format7 y
)

The secret is the line consisting of a single colon (:). It splits the code into 2 distinct sections, a (first) monadic and a (second) dyadic section.

If the x-argument is absent then the first (monadic) section (only) is run. We've included smoutput statements to show whichever block of code has been run.

What happens when there is an error?

Calling a verb with the wrong number of arguments results in domain error {36xlq4t}.

What does this mean in practice?

Like APL, an error message gets written to IJX. For example:

   '' format5 999
|domain error: format5
|   ''    format5 999

But unlike APL, the verb does not automatically suspend. J returns to an idle state, awaiting IJX input. So you don't have to clear the stack whenever the code crashes.

If you want the broken verb (or adverb, or conjunction) to suspend, in order say to leave work-nouns available for inspection, then you have to enable suspension. Thus:

(13!:0) 1   NB. reset stack and enable suspension
NB. (run the test expression...)
(13!:0) 0   NB. reset stack and disable suspension

There is a built-in debugger: Run > Debug....
Or you can experiment with manual stack control by looking-up the Help page for 13!: {36vo9sk}.

Some J-ers find little use in practice for the APL-like debugging facility, preferring instead to execute the offending verb line-by-line, or use smoutput to trace execution by displaying work-nouns and noun expressions in-flight.

So maybe this is a topic to leave for another day.

Seeing what words, of what kind, have been defined to-date

Restart J afresh and enter this into IJX:

   names''
   ]a=: 1+b=: 2
3
   plus=: +   NB. plus is a user-defined verb (a pretty elementary one)
   a plus b
6
   names''
a    b    plus
   names 0
a b
   names 3
plus


names''     ~~ ⎕NL 2 3 4
names 0     -- ⎕NL 2
names 3     -- ⎕NL 3
names 0 3   ~~ ⎕NL 2 3
names 1 2   ~~ ⎕NL 4

Maybe your APL doesn't implement (⎕NL 4)? Some do: they have an APL object that's coded like a function, but applies itself to actual functions to modify their behaviour. APL-ers call these super-objects "operators" -- and J-ers use that term also. But they prefer to talk of adverbs (1) and conjunctions (2).

At this stage you may not care to try defining your own adverbs, much less conjunctions. But the standard library stdlib.ijs contains several good examples you'll find useful, such as each. See {3ylp5bn} for a description of the contents of stdlib.ijs. The words defined by this script are visible in a normal J session, by a means to be described below.

Let's take note of the integers which universally stand for the different kinds of J word:

0  noun         ~~ variable, also used for the value assignable to a variable
1  adverb       ~~ single-function APL operator
2  conjunctions ~~ double-function APL operator
3  verb         ~~ function
4  verb         =  verb forced into being a DYADIC function
13 verb         =  verb converted into "tacit" format, if J can do it

The last two integers, 4 and 13, only hold good during the actual definition of verbs. Once they've been defined, all verbs are of type: 3.

The built-in verb: type tells you what type a given user-defined word is:

   type'a'
+----+
|noun|
+----+
   type 'a' ; 'b' ; 'plus'
+----+----+----+
|noun|noun|verb|
+----+----+----+

But... isn't J like APL: no reserved words?

Well... yes and no. Strictly yes, because words like names and type are defined somewhere (in just the same way you'd define them) in terms of J primitives. But J, as shipped, comes with these words automatically loaded -- and thus ready-defined.

I daren't say "built-in" because they can be un-built by you (if you're that unwise!)

However, when you type: names'' --you don't see them listed.

Let's look at their definitions:

   names
list_z_@nl
   type
{&(<;._1 '|invalid name|not defined|noun|adverb|conjunction|verb|unknown')@(2&+)@(4!:0)&boxopen

Okay... that's nothing we're going to understand today. Let's take it on faith that they work.

But the big question is... whereabouts are they defined? (names'' doesn't see them!)

The answer is: they're defined in a different locale {33nr3uw}.

The locales: base, z, j

You're working, by default, in a locale called base (unless you change it by using the word: cocurrent). But there's another important locale called z which happens to be chained to all others, so that its words are available to every locale. Normally, if a word is defined in another locale, then you need to tag its name with the locale name in order to run it.

For example: there's a noun called STARTUP in a locale called j. Here's how to see it, and how not to.

   STARTUP
|value error: STARTUP
   STARTUP_j_
~config\startup.ijs
   NB. --it's the location of your `startup.ijs` file
   NB. Another way to see it is to go to the locale: j
   cocurrent 'j'
   STARTUP
~config\startup.ijs
   NB. --and make sure you get back home afterwards, to avoid mischief...
   cocurrent 'base'

In other words, you can see the value of noun: STARTUP by tagging its name with j like this: STARTUP_j_, or you can navigate to the locale itself, and work inside it just as you work in base.

But words in locale: z are different: they behave as if they're honorary citizens of all other locales {3yh6sek}. Locale: z is said to be the parent locale of all other locales.

STARTUP_j_ is the address of your "startup file": startup.ijs. It is usually ~config/startup.ijs.-~

But startup.ijs doesn't exist in a fresh J installation.

We'll show you how to create it later.

Using LOBROW to get to know other locales

The locales which it's worth getting to know (using LOBROW) are z, j, jijs. They contain most "built-in" general-purpose J words, plus those implementing JFE. Others generally contain specialised packages, eg jbrowser.

LOBROW will tell you what locales are currently defined.

Numbered locales are created by the JFE or a package, generally as a copy of some other locale, or as scratch space. Thus LOBROW loads into its own locale: lobrow.

Instances of OOP objects are held as numbered locales. This should be borne in mind if you patch someone else's code at runtime: do you patch the instance or the template? Answer: it depends what copy of a given verb is being run.

Running an app in its own locale

Running an app in its own locale is a good idea, to avoid name-clashes and cluttering up the base locale, leaving it free for experiments.

You can make calc.ijs load and run in its own locale very easily. Insert the following statement at the top of the script (after the leading comments):

cocurrent 'calc'

Locale names don't clash with J words.

You can specify the name of an existing locale: the words are simply merged in.

Many scripts of utilities load tehmselves into the z locale this way.

You don't need to insert cocurrent'base' (say) at the bottom of the script. When it has loaded, the cocurrent setting reverts to what it was before loading (which is usually: base).

Meet your own personal Startup file

It's time to meet your Startup File. It's a real friend in need. But unlike a real-life friend you can fix it once-for-all and forget about it. A lot of J-ers do. But as a beginner you may feel the need to experiment with it, making it load words you use frequently.

Locate and open your startup.ijs. You can get at it by Edit > Configure...
Now choose: Category: Startup, then: Startup Script: Open.

If startup.ijs is absent, J will offer to create it for you.

Your Startup File is good for pre-loading the most-used libraries and packages, and for the occasional must-have word definition. (Though it's better to collect these into one or more separate scripts of utilities for ease-of-maintenance, as we do below).

Paste the following into your startup.ijs and save it:

require'strings'        NB. useful verbs go in locale: z
require'convert'        NB. structural utilities
require'dates'          NB. Tools menu requires: weekday

load'~user/handy.ijs'   NB. handy words
load'~user/lobrow.ijs'  NB. locale browser
load'~user/xp.ijs'      NB. expression explicator
load'~user/zulu.ijs'    NB. experimental data

The script zulu.ijs loads into its own locale: zulu. Use LOBROW to inspect it. It contains some simple test-data to experiment with various ways of keeping text lists, viz as:

  • boxed strings (zub, zulub)
  • space-separated string (zul, zulul)
  • LF-separated string (zuu, zuluu).
  • char-matrix (zux, zulux)

zub is just the first 3 elements of zulub, ditto the rest.

zulul is an alias of zulu.

It also defines verbs to convert any of these 4 list-formats into any other.

Warning: some of these are replicated by differently-named verbs in stdlib.ijs.

To find the verb for any given pair of zu-nouns, say zub, zux, take the last letters of each word to form the name: b2x. Then: b2x: zub --> zux, ie:

   zux -: b2x zub   NB. -: ~~ ≡
1

There's also a demo verb: phonetic which uses one of the test-data nouns (zulub) to convert an alpha string into the International Phonetic Alphabet. (Handy if you're phoning and it's a noisy line.)

Download the following scripts and move them to your ~user folder (enter: jpath'~user' to see where this resides):

  • A collection of handy words (which go into the z locale):

Wm yes check.png

  • A simple locale browser:

Wm yes check.png

  • A J expression decoder (which goes into the z locale):

Wm yes check.png

  • Some test data and conversion verbs for string/array experiments:

Wm yes check.png

Now exit and restart J.

You should now be able to run the words defined by these scripts.

Reading and writing J code

Whilst browsing code samples you will see perplexing examples of expressions like this:

   delstring=: 4 : ';(x E.r) <@((#x)&}.) ;.1 r=. x,y'

You expect decyphering such expressions will be laborious to start with (until J begins to make sense to you... as it will, soon enough).

But how do you even make a start at it? Here's where some of the "startup" utilities are useful.

Take the string which defines delstring above, and call xp with it:

   xp ';(x E.r) <@((#x)&}.) ;.1 r=. x,y'
+--+---------------------+
|; |Raze * Link          |
+--+---------------------+
|( |                     |
+--+---------------------+
|x |                     |
+--+---------------------+
|E.|* Member of Interval |
+--+---------------------+
|r |                     |
+--+---------------------+
|) |                     |
+--+---------------------+
|< |Box * Less Than      |
+--+---------------------+
|@ |Atop                 |
+--+---------------------+
|( |                     |
+--+---------------------+
|( |                     |
+--+---------------------+
|# |Tally * Copy         |
+--+---------------------+
|x |                     |
+--+---------------------+
|) |                     |
+--+---------------------+
|& |Bond / Compose       |
+--+---------------------+
|}.|Behead * Drop        |
+--+---------------------+
|) |                     |
+--+---------------------+
|;.|Cut                  |
+--+---------------------+
|1 |                     |
+--+---------------------+
|r |                     |
+--+---------------------+
|=.|Is (Local)           |
+--+---------------------+
|x |                     |
+--+---------------------+
|, |Ravel * Append       |
+--+---------------------+
|y |                     |
+--+---------------------+

Each J-word in turn is looked up and identified, except those atoms you can guess for yourself, like x, y, other variables and parentheses.

This helps you look them up in Voc {5up9gw}. This page will be your first destination for identifying a primitive. Unfortunately the explanations aren't always as clear as they might be. A new Voc is under development to remedy this: {2ubbdtp}. This has the advantage of being based on wiki pages, so it will grow gradually with more-and-more useful samples contributed by the wiki readership.

When it comes to writing your own code, things get really frustrating. Voc {5up9gw} is not that helpful, because you have to take a guess at which primitive you might need, and then look up how to use it. Whereas you can easily think of what APL primitives you'd use.

Instead, try your luck with this APL-to-J phrasebook {34mhmlw}. The correspondences are not exact: you will still have to study the chosen J primitive to see how it behaves. But at least it narrows the search.

Take a peek at other locales

Let's take a look inside every locale that's currently in existence. Locales come and go: JFE sees to that! It creates new locales for special tasks. It's how J achieves Object-Oriented Programming (OOP): by creating separate instances of some parent locale.

To start the browser, enter: load '~user/lobrow.ijs'

The top-left pane contains a list of all currently defined locales.

Click on a locale name.

All the words it contains are listed in the bottom-left pane.

Click on a word.

Its definition appears in the biggest pane.

You can edit a system word this way, redefining it in-flight. Typically you'd insert some probe like this:

 ZZ_base_ =: mylocalvar
...
 smoutput 'mylocalvar' ; mylocalvar

to take a snapshot (ZZ in the base locale) of some internal value (mylocalvar) constructed by some system J word, or output mylocalvar to the IJX session.

Raiding the JFE for useful techniques

As already stated, the JFE is a treasure trove of useful techniques. For instance, how to call the internet browser to display a given URL.

JFE uses the browser to show on-line Help. This is held as a collection of webpages which are not only installed locally (see them here:)

   open '/Applications/j602/help/index.htm'  NB. MacOS only
   open '~help/index.htm'                    NB. platform-independent

but are also available on the web {349ljo9}. JFE accesses the local collection, of course. But the technique is the same for browsing a remote page.

It just so happens the JFE menus are defined in a file called jijs.ijs (see it here:)

   open '~system/extras/util/jijs.ijs'

Now use Find to look for the line that reads:

   JIJS=: 0 : 0
NB. ...for M$ Windows
   JIJSMAC=: 0 : 0
NB. ...for MacOS.

You'll recognise the contents of JIJS (or JIJSMAC) from the definition of the noun CALC (the one the Form Editor generated, with menu stubs). Look for where the Help menu is defined. You see:

menupop "&Help";
menu helphelp "&Help" "" "" "";

The word helphelp identifies the handler: search on it and you see:

jijs_helphelp_button=: 3 : 'htmlhelp ''index.htm'''

which, as we've seen with eval, is equivalent to:

jijs_helphelp_button=: 3 : 0
htmlhelp 'index.htm'
)

So now we look for a J word: htmlhelp.

handy.ijs, which I've got you to load automatically via your startup.ijs, defines a word wh to do this in IJX:

   wh'htmlhelp'
+-+
|j|
+-+

If you don't want the box round it, unbox (>) the output like this: >wh'htmlhelp'

So... it's in locale j. Instead of using cocurrent'j' to navigate to it, simply append the locale name to the word, giving htmlhelp_j_ (called a locative) by J grammarians):

   htmlhelp_j_
3 : 0
f=. jpath '~help\',y
if. IFWINCE do.
  require '~system\extras\util\shellex.ijs'
  shellex f
else.
  require '~system\extras\util\browser.ijs'
  launch_jbrowser_ f
end.
)

which reveals the secret.

There's a word launch (in locale jbrowser, which doesn't appear until it's needed). It seems like it's going to be defined in browser.ijs (else why whould the programmer use a require to ensure it was loaded?)

require is like load except it doesn't reload if the given script is already loaded.

Let's take a look at it. Re-enter this line you can see, altering require to open:

  require '~system\extras\util\browser.ijs'
  open    '~system\extras\util\browser.ijs'

The contents of browser.ijs appear in a new IJS window.

You'll be able to see the code for launch.

So, to launch the browser to show a given webpage:

  • Choose your URL and assign it to f:
   f=: 'http://en.wikipedia.org/wiki/P-code_machine'
  • Re-execute the 2 lines of code we saw in the definition of htmlhelp_j_:
  require '~system\extras\util\browser.ijs'
  launch_jbrowser_ f

The browser will show the URL identified in verb: f.

Tacit definition of verbs, adverbs and conjunctions

Many J introductory texts extol the virtues of tacit definition, inviting the novice to think he or she will be expected to program primarily in this way.

I think that's a mistake. It may indeed turn out to be the case, but it will be your choice to do so, and your happy discovery that there are advantages in it.

For the novice arriving fresh from APL, I have this piece of (possibly heretical) advice:

Don't try to get your head round tacit definition. There are better things to do with your mind.

On the other hand, there's no reason to be afraid of it, or let anyone mystify it for you.

It's not as if tacit code is a distinct alternative syntax for the J language. Tacit and explicit code can be mixed. Or more accurately, tacit expressions may be embedded in explicit expressions, as we show with smoutput below.

Indeed, straightforward assignment of verbs, as we had earlier with:

   format=: format1

is an elementary form of tacit definition.

Here's one approach to tacit code which may appeal to some readers. It is just p-code {5hm6lj} for a compiled form of verb (adverb, conjunction). Some J programmers write it straight off. Some programmers write in 6502 assembler straight off. I used to. But it gave me brain-fever.

A  p-code machine, as you'll recall, is a (virtual) machine with a stack-based architecture, p-code operators taking the values they need from a system stack and placing the results back on the stack. It thus dispenses with parentheses and named storage locations, achieving code which consists of nothing but a string of virtual machine operations.

J's p-code is fancier than the Pascal compilers of the 1970s. It accommodates both x and y arguments, seeing they get to the right places. Writers of tacit J talk about hooks and forks, depending on where the x argument feeds into. But if you don't want to risk getting it wrong, let J do it for you.

As we've shown above with format03, format13 and format4, a 1-line explicit definition can be converted into a tacit definition by the trick of re-entering it with 13 : instead of 3 :.

Not every explicit definition can be p-coded in this way (in which case 13 : will return the definition unchanged).

Inclusion of NB. among other things will prevent it being converted to tacit form.

But, though I disparage its extolment, I use tacit code a lot. (Though I write none of it myself, unless it is very short, like 1&digit). Because tacit code has two enormous advantages:

  • It is usually far terser than the explicit form, so it is good for keeping lists of idioms {337nea9}, which, being well-tested, are things you never want to re-code by hand,
  • It can be confidently substituted into a definition (tacit or explicit) in place of its proverb (defined name having the verb as its value) -- though you're wise to set it in parentheses. Thus tacit J is algebraic... which so few programming languages are.

Example:

   smoutput $zux
3 7
   smoutput
0 0 $ 1!:2&2
   (0 0 $ 1!:2&2) $zux   NB. substituting for: smoutput
3 7
   0 0 $ 1!:2&2 $zux   NB. ...even without the parens
3 7

Mostly what defeats substitution without parentheses is when two numerals come together with a separating space -- because J will see them as a single vector constant.

Example: dbr (reset stack and disable suspension), used simply an example of a suitable Foreign (!:) cover-verb:

   require 'debug'   NB. to define: dbr
   dbr
13!:0
   dbr 0   NB. ...that works ok. But...
   13!:0  0
|rank error
|       13!:0 0
   (13!:0) 0   NB. bracket the old dbr verb ...that works ok.
   13!:0 [0   NB. split 0 0 somehow ...that works ok too.

What this means in practice is: take care when coding these features:

} (Amend)    ~~ indexed assignment
!: (Foreign) -- ⎕-variables

which often frustrate beginners, who fail to see what J is bitching about.

Assigning arguments to "work-variables" (pronouns), or judicious insertion of parentheses, eases the difficulty.

As with APL, much published code is sparing of parentheses. If you need to understand how the code works, try putting them back in as a first step. But the problem is self-correcting: you soon get a feel for where parentheses are needed. Ditto the need for work-variables (viz: almost never).

If you need to study a sparingly parenthesised definition, eg that of conl (predefined by colib.ijs) there is an alternative J word representation (5!:6) which inserts more parentheses:

   conl
18!:1@(, (0 1"_ #~ # = 0:))
   5!:6 <'conl'
(18!:1)@(, ((0 1"_) (#~) (# = (0:))))

To save you looking up Foreigns (!:), handy.ijs defines a word: rep, which shows a verb in various alternative representations:

   rep''   NB. give me a prompt...
atomic boxed tree linear paren explicit
   'paren' rep 'conl'   NB. or just the first letter will do.
(18!:1)@(, ((0 1"_) (#~) (# = (0:))))

Conclusion

That completes the day's work. You'll soon find you can make J do everything you could in APL. Now spend the rest of your long, happy life exploring the beauty of the language.

In a crash-course like this, we've had to omit some vital topics. Once you've written something useful, go to these Voc links and take a hard look at them:

  • Rank (") {35yw7ba}, a total re-think of APL's Each (¨)
  • Power (^:) {324qslh}, especially its use in Function-Inverse and Iterate-Till-No-More-Needed
  • Words/Sequential Machine (;:) {3857sd5}, a Turing Machine in a primitive
  • Tally/Copy (#) {39adwp9}, think APL's Expand (\)
  • Gerunds () [[1]], case-statements without control words
  • Fix (f.) {2vfefrt}, fully resolving words into primitives
  • Unicode (u:) {3y2slb3}, getting a firm grip on 2-byte chars and utf-8
  • Extended (x:) {3y6sksf}, indefinitely long integers as a docile new numeral

Then go back and rewrite your app in half the length with a quarter of the effort.

But before I finish, let me recommend At Play With J {33m6s4n}, by the late Eugene McDonnell. This book taught me J. It is largely self-contained, imparting all you need to know at the time, in a painless and entertaining way. But there's some smart stuff in there, which could take you years to find out for yourself.

And don't neglect to explore the J wiki {38kwwec} and sign-up for the welcoming and supportive J community forums {2u2fmlt} You'll need to contact JSoftware.com to join the mailing-lists (as explained in {2u2fmlt}) before you can be authorised to update the wiki. But there will be no obligation to buy anything.

Having said that, a visit to: {37p46ny} will enable the work to continue as a free service. [Not a valid URL in 2020!]

References

{33ta68u} TinyURL expansion -- http://tinyurl.com/33ta68u
{22mvx2n} J installation download -- http://www.jsoftware.com/stable.htm
{33ta68u} J in a Day -- http://www.jsoftware.com/jwiki/JinaDay
{38kwwec} J wiki -- http://www.jsoftware.com/jwiki
{2u2fmlt} J forums -- http://www.jsoftware.com/jwiki/System/Forums
{34agevb} J for the APL Programmer -- http://www.jsoftware.com/jwiki/Doc/J4APL
{349ljo9} Help -- http://www.jsoftware.com/help/index.htm
{22wvtqv} J Primer -- http://www.jsoftware.com/help/primer/contents.htm
{5up9gw} Voc -- http://www.jsoftware.com/help/dictionary/vocabul.htm
{3yhbsfa} Foreign (!:) -- http://www.jsoftware.com/help/dictionary/xmain.htm
{32nhxyb} Adverse (::) -- http://www.jsoftware.com/help/dictionary/d312.htm
{2u6qe74} Try/Catch (try.) -- http://www.jsoftware.com/help/dictionary/d312.htm
{2vnh8y7} J Constants -- http://www.jsoftware.com/help/dictionary/dcons.htm
{3xn3tm9} Control Structures -- http://www.jsoftware.com/help/dictionary/ctrl.htm
{36xlq4t} J Errors and Suspension -- http://www.jsoftware.com/help/dictionary/dictj.htm
{36vo9sk} Debug (13!:) -- http://www.jsoftware.com/help/dictionary/dx013.htm
{2wc7upd} wd -- http://www.jsoftware.com/help/user/wd_commands.htm
{34mhmlw} APL2J -- http://www.jsoftware.com/jwiki/APL2JPhraseBook
{32j6ot6} LOBROW -- http://www.jsoftware.com/jwiki/IanClark/LoBrow
{2ubbdtp} NuVoc -- http://www.jsoftware.com/jwiki/NuVoc
{33m6s4n} APWJ -- http://www.jsoftware.com/jwiki/At%20Play%20With%20J
{33nr3uw} Locale -- http://www.jsoftware.com/help/primer/locale.htm
{3yh6sek} 'z' locale -- http://www.jsoftware.com/help/primer/z_locale.htm
{38onjdv} Definition Summaries -- http://www.jsoftware.com/help/user/sys_lista.htm
{3ylp5bn} stdlib words -- http://www.jsoftware.com/jwiki/stdlib.ijs
{5hm6lj} p-code -- http://en.wikipedia.org/wiki/P-code_machine
{337nea9} J idioms -- http://www.jsoftware.com/help/phrases/contents.htm
{35yw7ba} Rank (") -- http://www.jsoftware.com/help/dictionary/d600n.htm
{3857sd5} Words/Seq Mc (;:) -- http://www.jsoftware.com/help/dictionary/d332.htm
{39adwp9} Tally/Copy (#) -- http://www.jsoftware.com/help/dictionary/d400.htm
{38s2xo4} Gerunds () -- http://www.jsoftware.com/help/dictionary/d610.htm
{2vfefrt} Fix (f.) -- http://www.jsoftware.com/help/dictionary/dfdot.htm
{3y2slb3} Unicode (u:) -- http://www.jsoftware.com/help/dictionary/duco.htm
{3y6sksf} Extended (x:) -- http://www.jsoftware.com/help/dictionary/dxco.htm
{324qslh} Power (^:) -- http://www.jsoftware.com/help/dictionary/d202n.htm
{37p46ny} Donate -- http://www.jsoftware.com/#/donate


(Contributed by Ian Clark.)