Chapter 24: Names and Locales
In this chapter we look at locales. The interest of locales is twofold:
as a way of organizing large programs, and (as we will come to in the next
chapter) as the basis of object-oriented programming in J.
24.1 Background
It is generally agreed that a
large program is best developed in several parts which are,
as much as possible, independent of each other.
For example, an independent
part of a larger program might be a collection of statistical functions,
with its own script-file.
For the things defined in an independent script,
we expect to choose names for those things
more or less freely,
without regard for what names may be defined in other scripts.
Clearly there may be a problem in combining independent scripts:
what if the same name accidentally receives different definitions
in different scripts?
The J facility of the "locale" gives a way to deal with this problem.
24.2 What are Locales?
After entering an assignment of the form (name =: something)
we say we have a definition of name.
Every definition is stored in some region of the memory of the J system
called a "locale".
Roughly speaking, locales are to definitions as directories are to files.
The important features of locales are:
- There can be several different locales existing at the same time.
- Each locale stores a collection of definitions.
- The same name can occur at the same time in different locales with
different definitions.
Hence a name of the form
"name N as defined in locale L" is uniquely defined, without
conflict. Such a name
can be written as N_L_ (N underbar L underbar) and is called a
"locative name". Finally
- At any one time, only one locale is current. The current locale is
the one whose definitions are
available for immediate use.
Hence a plain name N commonly means
"N as defined in the current locale".
Locales are neither nouns, verbs, adverbs nor
conjunctions: that is, locales are not values which can be
assigned to variables or be passed as arguments to functions.
They do have names,
but whenever we need to refer to a locale by name we do so
either with special syntactic forms, (locative names such as
N_L_) or by quoting the name to form a string.
24.3 Example
Suppose we are interested in the correlation
between the price of whisky and the general level of employee salaries.
Suppose also that we have available two scripts,
of independent origin, one with economic data and the
other with statistical functions. These script-files
might have been created like this:
(0 : 0) (1 !: 2) < 'economic.ijs'
y =: 1932 1934 1957 1969 1972 NB. years
s =: 1000 1000 3000 9000 11000 NB. salaries
p =: 1.59 1.68 2.00 4.50 5.59 NB. prices
)
(0 : 0) (1 !: 2) < 'statfns.ijs'
m =: +/ % # NB. Mean
n =: - m NB. Norm
v =: m @: *: @: n NB. Variance
s =: %: @: v NB. Standard Deviation
c =: m @: (*&n) NB. Covariance
r =: c % (*&s) NB. Correlation Coefficient
)
We aim to load these two scripts,
and then hope to compute the coefficient of correlation between prices p
and salaries s as the value of the expression (p r s).
Unfortunately we can see that the name s
means different things in the different scripts.
If we were to load both scripts into the same locale,
one definition of s would overwrite the other.
The remedy is to load the two scripts into different locales.
There is always a locale named base, and by default this is usually
current.
We load economic.ijs into the current locale (base)
with the built-in verb (0 !: 0).
(0 !: 0) < 'economic.ijs'
Next we load statfns.ijs into another locale which we choose
to call, say, stat. To do this with the minimum
of new apparatus we can use the built-in verb (18 !: 4).
(18 !: 4) < 'stat'
(0 !: 0) < 'statfns.ijs'
(18 !: 4) < 'base'
The first line creates the stat locale and makes it current. The second
line loads
statfns.ijs into the now-current locale stat. The third line makes
the base locale current again, to restore the status quo.
At this point our data variables s and p are available because they
are in
base which is current. The correlation-coefficient
function r is not yet available, because it is in
stat which is not current.
The next step is to define the correlation-coefficient
function to be r-as-defined-in-locale- stat, using the locative form
of name
r_stat_
corr =: r_stat_
corr is available because it has just been defined in base
(because base is current).
Everything we need is now available. We can compute the correlation
between salaries
and prices.
s corr p |
p corr s |
p corr p |
0.993816 |
0.993816 |
1 |
24.3.1 Review
What we have seen is the use of locative names to resolve name-conflicts
between independent scripts. What it took was a relatively small amount
of ad-hoc further definition.
In this tiny example the conflict was easily identified and could be easily
fixed by editing one of the scripts. However, the point is that we aim
to avoid tampering with independent scripts
to get them to work together.
24.4 The Current Locale
Several locales may coexist, but at any one time
only one is current. There is a built-in verb
(18 !: 5) which tells us the name of the current locale.
(18 !: 5) '' NB. show name of current locale
+----+
|base|
+----+
The significance of the current locale is that
it is in the current locale that simple names are evaluated:
s
1000 1000 3000 9000 11000
Notice that we get the value of s as defined in
script economic.ijs which we loaded into base, and not the value
of s in statfns.ijs which was loaded into locale stat.
It is the current locale in which new definitions
are stored. To see what names are defined
in the current locale we can use
the built-in verb (4 !: 1) with an argument
of 0 1 2 3.
(4 !: 1) 0 1 2 3 NB. show all names in current locale
+--+--+----+---------+--------+-------+------+-------+---------+---------+---------+-+-----+-+-+
|CH|IP|corr|indexfile|indexing|is_char|is_int|is_list|is_number|is_scalar|is_string|p|print|s|y|
+--+--+----+---------+--------+-------+------+-------+---------+---------+---------+-+-----+-+-+
foo =: +/
(4 !: 1) 0 1 2 3
+--+--+----+---+---------+--------+-------+------+-------+---------+---------+---------+-+-----+-+-+
|CH|IP|corr|foo|indexfile|indexing|is_char|is_int|is_list|is_number|is_scalar|is_string|p|print|s|y|
+--+--+----+---+---------+--------+-------+------+-------+---------+---------+---------+-+-----+-+-+
As we saw above, we can change the current locale with the built-in verb
(18 !: 4). We can make the stat locale current with:
(18 !: 4) < 'stat'
and now we can see what names are defined in this locale
with:
(4 !: 1) 0 1 2 3
+-+-+-+-+-+-+
|c|m|n|r|s|v|
+-+-+-+-+-+-+
and return to base again
(18 !: 4) < 'base'
24.5 The z Locale Is Special
The locale named z is special
in the following sense.
When a name is evaluated,
and a definition for that name is not present
in the current locale, then the z locale is automatically
searched for that name. Here is an example.
We put into localez a definition of a
variable q, say.
(18 !: 4) < 'z'
q =: 99
(18 !: 4) < 'base'
Now we see that q is not present in the current
locale (base) but nevertheless we can
evaluate the simple name q to get its value as defined in locale z.
(4 !: 1) 0 1 2 3
+--+--+----+---+---------+--------+-------+------+-------+---------+---------+---------+-+-----+-+-+
|CH|IP|corr|foo|indexfile|indexing|is_char|is_int|is_list|is_number|is_scalar|is_string|p|print|s|y|
+--+--+----+---+---------+--------+-------+------+-------+---------+---------+---------+-+-----+-+-+
q
99
Since we can find in z things which are not in base,
locale z is the natural home
for functions of general utility. On starting a J
session, locale z is automatically populated
with a collection of useful predefined "library"
functions.
The names of these functions in the z locale are
all available for
immediate use, and yet the names, of which there are more than 100,
do not clutter the base locale.
We saw above the use of built-in verbs such as (18 !: 4)
and (4 !: 1). However
the library verbs of locale z are often more convenient.
Here is a small selection:
coname '' | show name of current locale |
conl 0 | show names of all locales |
names '' | show all names in current locale |
nl '' | show all names in current locale (as a boxed list) |
cocurrent 'foo' | locale foo becomes current |
clear 'foo' | remove all defns from locale foo |
coerase 'A';'B';'C' | erase locales A B and C |
We have seen that when a name is not found in the current locale,
the search proceeds automatically to the z locale.
In other words, there is what is called a "path" from every locale to
the z locale. We will come back to the subject of paths below.
24.6 Locative Names and the Evaluation of Expressions
24.6.1 Assignments
An assignment of the form n_L_ =: something
assigns the value of something to the name n in locale L.
Locale L is created if it does not already exist.
For example:
n_L_ =: 7
creates the name n in locale L with value 7.
At this point it will be helpful to introduce
a utility-function to view all the definitions
in a locale.
We put this view function into locale z
:
VIEW_z_ =: 3 : '(> ,. ('' =: ''&,)@:(5!:5)"0) nl '''''
view_z_ =: 3 : 'VIEW__lo '''' [ lo =. < y'
If we make a few more definitions:
k_L_ =: 0
n_M_ =: 2
we can survey what we have in locales L and M:
view 'L' |
view 'M' |
k =: 0
n =: 7 |
n =: 2 |
Returning now to the theme of assignments, the scheme is:
if the current locale is L, then
(foo_M_ =: something) means:
- evaluate something in locale L to get value V say.
- cocurrent 'M'
- foo =: V
- cocurrent 'L'
For example:
cocurrent 'L'
view 'L' |
view 'M' |
k_M_ =: n-1 |
view 'M' |
k =: 0
n =: 7 |
n =: 2 |
6 |
k =: 6
n =: 2 |
24.6.2 Evaluating Names
Now we look at locative names occurring in expressions.
The scheme (call this scheme 2) is:
if the current locale is L then (n_M_) means
- cocurrent 'M'
- evaluate the name n to get a value V
- cocurrent 'L'
- V
For example:
cocurrent 'L'
view 'L' |
view 'M' |
n_M_ |
k =: 0
n =: 7 |
k =: 6
n =: 2 |
2 |
24.6.3 Applying Verbs
Consider the expression (f_M_ n).
This means: function f (as defined in locale M)
applied to an argument n (as defined in the current locale)
In this case, the application of f to n
takes place in locale M. Here is an example:
u_M_ =: 3 : 'y+k'
cocurrent 'L'
view 'L' |
view 'M' |
u_M_ n |
k =: 0
n =: 7 |
k =: 6
n =: 2
u =: 3 : 'y+k' |
13 |
We see that the argument n comes from the current locale
L, but the constant k comes from
the locale (M) from which we took verb u.
The scheme (call it scheme 3) is:
if the current locale is L ,
then (f_M_ something)
means:
- evaluate something in L to get a value V say
- cocurrent 'M'
- in locale M, evaluate the expression f V to get
a value R say
- cocurrent 'L'
- R
Here is another example. The verb g
is taken from the same locale in which f is found:
g_L_ =: +&1
g_M_ =: +&2
f_M_ =: g
cocurrent 'L'
view 'L' |
view 'M' |
f_M_ k |
g =: +&1
k =: 0
n =: 7 |
f =: g
g =: +&2
k =: 6
n =: 2
u =: 3 : 'y+k' |
2 |
24.6.4 Applying Adverbs
Suppose A_X_ is an adverb in locale X.
The application of A_X_ to an argument takes
place in locale X rather than in the current locale.
To demonstrate this, we start by entering definitions in fresh locales
X and Y.
A_X_ =: 1 : 'u & k' NB. an adverb
k_X_ =: 17
k_Y_ =: 6
now make Y the current locale:
cocurrent 'Y'
and apply adverb A_X_ to argument + .
view 'X' |
view 'Y' |
+ A_X_ |
A =: 1 : 'u & k'
k =: 17 |
k =: 6 |
+&17 |
Evidently the result is produced by taking k
from locale X rather than from the current locale which is Y.
The scheme is that if the current locale is Y,
and A is an adverb, the expression
f A_X_ means:
- evaluate f in locale Y to get a value F say.
- cocurrent X
- evaluate F A in locale X to get a result G say.
- cocurrent Y
- G
24.7 Paths
Recall that the z locale contains useful "library" functions, and that
we said there is
a path from any locale to z.
We can inspect the path from a
locale
with the library verb copath;
we expect the path from locale base to be just z.
copath 'base' NB. show path
+-+
|z|
+-+
A path is represented as a
(list of) boxed string(s). We can build our own structure of search-paths
between locales. We will give base a path to
stat and then to z, using dyadic copath.
('stat';'z') copath 'base'
and check the result is as expected:
copath 'base'
+----+-+
|stat|z|
+----+-+
With this path in place, we can, while base
is current, find names in base, stat
and z.
cocurrent 'base'
s NB. in base
1000 1000 3000 9000 11000
r NB. in stat
c % *&s
q NB. in z
99
Suppose we set up a path from L to M. Notice
that we want every path to terminate at locale z,
(otherwise we may lose access to the useful
stuff in z) so we make the path go from L to M
to z.
('M';'z') copath 'L'
If we access a name along a path,
there is no change of current locale. Compare
the effects of referring to verb u
via a locative name and searching for u along a
path.
cocurrent 'L'
view 'L' |
view 'M' |
u_M_ 0 |
u 0 |
g =: +&1
k =: 0
n =: 7 |
f =: g
g =: +&2
k =: 6
n =: 2
u =: 3 : 'y+k' |
6 |
0 |
We see that in evaluating (u_M_ 0) there is a change of
locale to M, so that the variable k is picked up
with its value in M of 6. In evaluating (u 0), where u
is found along the path, the variable k is picked up from the
current locale, with its value in L of 0.
When a name is found along a path, it is as though
the definition were temporarily copied into
the current locale. Here is another example.
view 'L' |
view 'M' |
f_M_ 0 |
f 0 |
g =: +&1
k =: 0
n =: 7 |
f =: g
g =: +&2
k =: 6
n =: 2
u =: 3 : 'y+k' |
2 |
1 |
24.8 Combining Locatives and Paths
We sometimes want to populate a locale
with definitions from a script-file.
We saw above one way to do this:
in three steps:
(1) use cocurrent (or 18 !: 4) to move to the
specified locale.
(2) execute the script-file with 0!:0
(3) use cocurrent (or 18 !: 4) to return to the original locale.
A neater way is as follows. We first define:
POP_z_ =: 0 !: 0
and then to populate locale Q
say, from file economic.ijs, we can write:
POP_Q_ < 'economic.ijs'
which works like this:
- The POP verb is defined in locale z.
- Encountering POP_Q_ < ... the system makes locale
Q temporarily current, creating Q if it does not already exist.
- The system looks for a definition of POP.
It does not find it in Q
, because POP is of course defined in locale z.
- The system then looks along the path from Q
to z and finds POP. Note that the current locale
is still (temporarily) Q.
- The POP verb is applied to its argument, in
temporarily-current locale Q.
- The current locale is automatically restored to
whatever it was beforehand.
Back to base. (If we are nipping about between locales it is advisable to
keep
track of where we are.)
cocurrent <'base'
24.9 Indirect Locatives
A variable can hold the name of a locale as a
boxed string. For example, given that M is a
locale,
loc =: < 'M'
Then a locative name such as k_M_ can be
written equivalently in the form k__loc
(u underscore underscore loc)
k_M_
6
k__loc
6
The point of this indirect form is that it
makes it convenient to supply locale-names as arguments to functions.
NAMES =: 3 : 0
locname =. < y
names__locname ''
)
NAMES 'L'
g k n
24.10 Erasing Names from Locales
Suppose we create a variable with the name var, say,
var =: 'hello'
and demonstrate that it exists, that is, that the name var is
one of the names in the namelist of the base locale:
(<'var') e. nl_base_ ''
1
Now we can erase it with the erase library verb:
erase <'var'
1
and demonstrate that it no longer exists
(<'var') e. nl_base_ ''
0
Now suppose that we create a variable foo, say,
in the base
locale, and another, also called foo, in the z locale.
Recall that there is always a path from base to z
foo =: 'hello'
foo_z_ =: 'goodbye'
we demonstrate they both exist:
(<'foo') e. nl_base_ ''
1
(<'foo') e. nl_z_ ''
1
erase foo from base, demonstrate that it has gone
but that foo in z is still there:
erase <'foo' |
(<'foo') e. nl_base_ '' |
(<'foo') e. nl_z_ '' |
1 |
0 |
1 |
Now if we erase again, foo will be found along
the path and erased from z.
erase <'foo' |
(<'foo') e. nl_base_ '' |
(<'foo') e. nl_z_ '' |
1 |
0 |
0 |
This is the end of Chapter 24
|