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.
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:
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
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.
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) < 'c:\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) < 'c:\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) < 'c:\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) < 'C:\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.
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 +----+-+-+-+ |corr|p|s|y| +----+-+-+-+ foo =: +/ (4 !: 1) 0 1 2 3 +----+---+-+-+-+ |corr|foo|p|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 +----+---+-+-+-+ |corr|foo|p|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:
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
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:
Returning now to the theme of assignments, the scheme is: if the current locale is L, then (foo_M_ =: something) means:
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
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'
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:
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'
24.6.4 Applying Adverbs
To begin, note that when an adverb is applied, names of verbs do not get evaluated.
The result is an expression for a verb in terms of w, the argument, and z which occurrs in the definition of ADV
Here now is an example of an adverb referred to by a locative name. We enter definitions in fresh locales P and Q.
u_P_ =: *&2 v_P_ =: *&3 u_Q_ =: *&7 v_Q_ =: *&5 A_Q_ =: @: v
make P the current locale, and apply adverb A_Q_ to argument u to get verb D:
Evidently the result 6 is obtained by taking u and v from the current locale which is P.
The scheme is that if the current locale is P, and A is an adverb, the expression u A_Q_ means:
B_Q_ =: (@: v) f.
Evidently the argument u and the auxiliary verb v are both taken from locale Q.
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.
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.
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_ < 'c:\economic.ijs'
which works like this:
Back to base. (If we are nipping about between locales it is advisable to keep track of where we are.)
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' ADV g k n w z
This is the end of Chapter 24
Table of Contents
Copyright © Roger Stokes 2002. This material may be freely reproduced, provided that this copyright notice is also reproduced.
last updated 15 Mar 2002