Help / Learning / Ch 24: Names and Locales

From J Wiki
Jump to navigation Jump to search


>> << Pri JfC LJ Phr Dic Voc !: Rel NuVoc wd Help Learning J


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. The resulting long list of names can be conveniently displayed with the library-verb list .

   list (4 !: 1) 0 1 2 3  NB. show all names in current locale
ASSERTING CH        IP        RUN       RUNR      TD        THIS      
and       cd        corr      dir       drop      e         first     
fst       hello     implies   indexfile indexing  is_bool   is_box    
is_char   is_cmplx  is_extint is_float  is_int    is_list   is_number 
is_rat    is_real   is_scalar is_string last      most      not       
p         print     pwd       rest      run       s         snd       
take      thd       y                                                 

We can define a new verb, and see its name appear in the list:

   foo  =: +/
   list (4 !: 1) 0 1 2 3 
ASSERTING CH        IP        RUN       RUNR      TD        THIS      
and       cd        corr      dir       drop      e         first     
foo       fst       hello     implies   indexfile indexing  is_bool   
is_box    is_char   is_cmplx  is_extint is_float  is_int    is_list   
is_number is_rat    is_real   is_scalar is_string last      most      
not       p         para      print     pwd       rest      run       
s         snd       take      thd       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 locale z a definition of a

variable q, say.
   (18 !: 4) < 'z'
   q =: 99
   (18 !: 4) < 'base'
   

Now we see that the name q is not present in the current locale (base):

   list (4 !: 1) 0 1 2 3 
ASSERTING CH        IP        RUN       RUNR      TD        THIS      
and       cd        corr      dir       drop      e         first     
foo       fst       hello     implies   indexfile indexing  is_bool   
is_box    is_char   is_cmplx  is_extint is_float  is_int    is_list   
is_number is_rat    is_real   is_scalar is_string last      most      
not       p         para      print     pwd       rest      run       
s         snd       take      thd       y                             
   

but nevertheless we can evaluate the simple name q to get its value as defined in locale z.

   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:

  1. evaluate something in locale L to get value V say.
  2. cocurrent 'M'
  3. foo =: V
  4. 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

  1. cocurrent 'M'
  2. evaluate the name n to get a value V
  3. cocurrent 'L'
  4. 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:

  1. evaluate something in L to get a value V say
  2. cocurrent 'M'
  3. in locale M, evaluate the expression f V to get a value R say
  4. cocurrent 'L'
  5. 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:

  1. evaluate f in locale Y to get a value F say.
  2. cocurrent X
  3. evaluate F A in locale X to get a result G say.
  4. cocurrent Y
  5. 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:

  1. The POP verb is defined in locale z.
  2. Encountering POP_Q_ < ... the system makes locale Q temporarily current, creating Q if it does not already exist.
  3. The system looks for a definition of POP. It does not find it in Q , because POP is of course defined in locale z.
  4. The system then looks along the path from Q to z and finds POP. Note that the current locale is still (temporarily) Q.
  5. The POP verb is applied to its argument, in temporarily-current locale Q.
  6. 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


NEXT
Table of Contents
Index


The examples in this chapter were executed using J version 701. This chapter last updated 18 Jul 2013
Copyright © Roger Stokes 2013. This material may be freely reproduced, provided that acknowledgement is made.


>> << Pri JfC LJ Phr Dic Voc !: Rel NuVoc wd Help Learning J