Vocabulary/NounExplicitDefinition

From J Wiki
Jump to: navigation, search

Back to: Vocabulary

Defining a noun as an explicit entity using (:)

A noun is usually created as a noun phrase, i.e. a phrase that evaluates to a noun.

Typically the noun thus created is straightaway assigned to a name in order to create what other programming languages call a (named) variable.

Example:

   ] z=: 'alpha',LF,'bravo',LF,'charlie',LF
alpha
bravo
charlie

   NB. Note how that trailing LF gives a trailing blank line

LF is a

  • Standard Library word(s) residing in the 'z'-locale.
  • Defined in the factory script stdlib.ijs.
  • View definition(s) by entering in the J session:  open'stdlib'


Defining a LF-separated string

But you can also create the same noun like this:

   z=: noun define
alpha
bravo
charlie
)

assert z -: 'alpha',LF,'bravo',LF,'charlie',LF

 noun define is equivalent to the phrase:  0 : 0

This is useful when you need to represent a table z inside a script, in the form in which you'd best like to visualize it.

If you define z in the above way, you always get a final linefeed character (LF). Sometimes this is inconvenient because some algorithms may take this to represent a final empty row.

You can drop the final LF like this:

   z=: }: noun define
alpha
bravo
charlie
)

However in general it is wise to retain it. Some utility verbs tolerate its (possible) presence. Additionally if you think of LF as being a line terminator, not a line separator, then every line is correctly terminated as things stand. Also the number of LF bytes is equal to the number of lines, so you can count lines by counting the LF characters

   +/z=LF

Defining a list of boxed strings

At first sight  noun define only lets you define a noun which is a LF-separated string, i.e. a list of bytes which is not actually a table, but only looks like one when displayed in the J session because it happens to contain linefeed characters (LF).

However you can build any type of noun by variations on the general principle

   z=: convert noun define
...
)

with a suitable choice of the verb: convert.

To build a list of boxed strings, the choice is simply cutopen in place of convert

   z=: cutopen noun define
alpha bravo
charlie
delta echo foxtrot
golf
)
   z
+-----------+-------+------------------+----+
|alpha bravo|charlie|delta echo foxtrot|golf|
+-----------+-------+------------------+----+

cutopen is a

  • Standard Library word(s) residing in the 'z'-locale.
  • Defined in the factory script stdlib.ijs.
  • View definition(s) by entering in the J session:  open'stdlib'

Instead of cutopen, you sometimes see Cut (;.) used with appropriate operands, which gives the same result

   z=: <;._2 noun define
alpha bravo
charlie
delta echo foxtrot
golf
)
   z
+-----------+-------+------------------+----+
|alpha bravo|charlie|delta echo foxtrot|golf|
+-----------+-------+------------------+----+
)

Defining a table of characters

If you apply Open (>) to a list of boxed strings, the result is a table of characters. So this is an easy modification of the foregoing example

   z=: > cutopen noun define
alpha bravo
charlie
delta echo foxtrot
golf
)

   $ z
4 18
   z
alpha bravo
charlie
delta echo foxtrot
golf

Defining a table of numbers

As stated above, with a suitable choice of the verb convert you can build a noun of any type and rank. For example, a table of numbers.

A J beginner might think that the only sensible way to define a 2-by-3 table of numbers inside a script is by reshaping a list of numbers specified as a constant like this:

   n=: 2 3  $  100 101 102 200 201 202

But this has the disadvantage of being hard to visualize, especially for large tables.

Another way is to build up the table n row-by-row, like this:

   n=: 0 3 $ 0
   n=: n , 100 101 102
   n=: n , 200 201 202

which does at least show the layout of n. But it has the disadvantage of entailing a separate execution for each line. This is not in the spirit of J, which lets you do better than that.

Let's write down the table n in the form we'd prefer to visualize it, viz directly as a 2-by-3 table, but within the definition of a LF-separated string, z

   z=: noun define
100 101 102
200 201 202
)

Now convert it in stages to any shape and type of n you like

   ]ztable=: >cutopen z   NB. converts "lines" to rows in a table of rank 2
100 101 102
200 201 202
   $ztable                NB. like z, ztable is (bytes)
2 11
   $ n=: ". ztable        NB. but n is (numbers)
2 3
   -n
_100 _101 _102
_200 _201 _202

You can do all this in one sentence — the very sentence which assigns the newly-built noun to the name: n

   n=: ". >cutopen noun define
100 101 102
200 201 202
)

cutopen, noun and define are

  • Standard Library word(s) residing in the 'z'-locale.
  • Defined in the factory script stdlib.ijs.
  • View definition(s) by entering in the J session:  open'stdlib'


Building the state transition table of a sequential machine

We turn now to building a brick, i.e. a rank 3 array, which at first sight doesn't lend itself to a variation on

   z=: convert noun define
...
)

But it does benefit from being visualized and maintained in table form.

Consider the primitive: Sequential Machine (;:).

The dyadic phrase:  x ;: y splits string 'y' into boxed words according to a syntax defined by the left-hand argument x.

The monadic phrase:  ;: y is the same as:  x ;: y but with a special built-in default value of x which implements a sequential machine to treat y as J code, and split it into words accordingly.

The chief and most critical part of this default value of x is the state transition table, defined in JDic:d332 like this:

sj=: _2]\"1 }.".;._2 noun define
' X    S    A    N    B    9    D    C    Q ']0
 1 1  0 0  2 1  3 1  2 1  6 1  1 1  1 1  7 1  NB. 0 space
 1 2  0 3  2 2  3 2  2 2  6 2  1 0  1 0  7 2  NB. 1 other
 1 2  0 3  2 0  2 0  2 0  2 0  1 0  1 0  7 2  NB. 2 alp/num
 1 2  0 3  2 0  2 0  4 0  2 0  1 0  1 0  7 2  NB. 3 N
 1 2  0 3  2 0  2 0  2 0  2 0  5 0  1 0  7 2  NB. 4 NB
 9 0  9 0  9 0  9 0  9 0  9 0  1 0  1 0  9 0  NB. 5 NB.
 1 4  0 5  6 0  6 0  6 0  6 0  6 0  1 0  7 4  NB. 6 num
 7 0  7 0  7 0  7 0  7 0  7 0  7 0  7 0  8 0  NB. 7 '
 1 2  0 3  2 2  3 2  2 2  6 2  1 2  1 2  7 0  NB. 8 ''
 9 0  9 0  9 0  9 0  9 0  9 0  9 0  9 0  9 0  NB. 9 comment
)

This shows one way of handling row and column labels in a table of numbers. It also shows how to make a rank-3 table.

A key point about the state transition table is that it must be rank-3, the last dimension consisting of pairs of numbers. Our technique primarily yields a rank-2 array of numbers, which then needs to be reshaped.

However there is a simple trick to temporarily eliminate the last dimension (provided it consists just of number pairs):

  • Combine each pair into a single (complex) number
  • Drop the (non-numeric) labels before converting the bytes to numbers by the more straightforward technique of using (}.)
  • Expand the complex numbers into pairs of integers using (+.) to restore the 3rd dimension.

This lets us simplify the table definition by adapting our earlier use of:  >cutopen

sk=: +. ". (1 _11) }. >cutopen (0 : 0)
 X    S    A    N    B    9    D    C    Q
1j1  0j0  2j1  3j1  2j1  6j1  1j1  1j1  7j1  0 space
1j2  0j3  2j2  3j2  2j2  6j2  1j0  1j0  7j2  1 other
1j2  0j3  2j0  2j0  2j0  2j0  1j0  1j0  7j2  2 alp/num
1j2  0j3  2j0  2j0  4j0  2j0  1j0  1j0  7j2  3 N
1j2  0j3  2j0  2j0  2j0  2j0  5j0  1j0  7j2  4 NB
9j0  9j0  9j0  9j0  9j0  9j0  1j0  1j0  9j0  5 NB.
1j4  0j5  6j0  6j0  6j0  6j0  6j0  1j0  7j4  6 num
7j0  7j0  7j0  7j0  7j0  7j0  7j0  7j0  8j0  7 '
1j2  0j3  2j2  3j2  2j2  6j2  1j2  1j2  7j0  8 ''
9j0  9j0  9j0  9j0  9j0  9j0  9j0  9j0  9j0  9 comment
)
   sk -: sj
1