Studio/Iterating with Class Verbs
Lab Iterating with Class Verbs Author Oleg Kobchenko <olegyk@yahoo.com>, December 1998 Download {{tick|File:LabIterate.ijt }}{{tick|File:LabIterate j401.ijt
|}
Introduciton
There have been discussions in JForum on iterating over a group of objects with verbs common to their classes.
In many OOP languages there are such groups for storing objects are called collections'. Hence, a method is applied to an indexed item rather than to an object directly.
Typically these uniform objects are nameless, and are accessed through indices. In C++ we would have something like:
dump (Item x) {out << x.value;} main () { Collection c = new Collection(); c.append(new Item(10)); c.append(new Item(20)); out << c.item(0).add(c.item(1)); for (i = 0 ; i <= c.count ; i++) {out << i.value} c.foreach(dump); }
In J the official means of class verb application to objects is in named style:
obj=. ''conew'myclass' myverb__obj ''
This is interpreted by the system as application of verb myverb, defined in class 'myclass' in the locale obj.
The second form of the same invocation is using the number of the object locale:
>obj 21 myverb_21_ ''
Both these forms are hardwired to the syntax. Such form of call syntactically produces a single entry
;:'myverb__obj' +-----------+ |myverb__obj| +-----------+ ;:'myverb_21_' +----------+ |myverb_21_| +----------+
Purpose
Any interference with this syntax fails:
myverb__(obj) '' NB. this is reference to base |value error: myverb__ NB. locale | myverb__(obj)'' myverb_(obj)_ '' NB. and this is a syntax error |ill-formed name: myverb_
Our target is to be able to indicate the object indirectly, which symbolically can be expressed as:
myverb__(obj) ''
Or iterate over a collection of objects:
myverb__(obj1,obj2,obj3) ''
A special interest would be the ability to iterate also over a collection of class verbs in a single call, which is usually absent in traditional OOP, but makes sense in J:
(meth1`meth2`meth3)__obj
Example with J locales
As a subject area we will chose the namespace model of J, which is familiar and always available. There are typical uses of locale switching technique:
aa=: i.3 nl'' NB. names in current locale +--+ |aa| +--+ nl_j_ 0 NB. nouns in j locale +-----+-------+--------+-----------+---------+------+--------- |BOXES|BROWSER|DIRTREEX|DISPLAYLOAD|EPSREADER|FORMAT|FORMSIZES... +-----+-------+--------+-----------+---------+------+--------- nl_z_ 1 NB. adverbs in z locale +------+----+-----+-----------+---+-------+-----+----+----+--- |define|each|every|fapplylines|inv|inverse|items|leaf|rows|rxa... +------+----+-----+-----------+---+-------+-----+----+----+---
But how can we get, say, all adverbs from several locales at once? Something like:
nl__(z,j) 1
or we have a list of locales and want to study the ith element
nl__(i{list)
Object dereferencing in J
There are several ways of indirect object reference in J.
1. Emulate the behavior of the system
a. switch to object's locale a. invoke the verb a. switch to current locale a. return the result
From Henry Rich (adapted by Oleg Kobchenko for j50x+):
inlocalesx_z_=: 1 : '(u@] [ 18!:4@[)"0 _ ([ 18!:4) (18!:5)@(''''"_)' (nl 6) #@nl inlocalesx '' NB. count of names 1 89 14 45 287 185 35 1 1 1 247 (nl 6) <@$@:>@nl inlocalesx '' NB. names matrix shapes +---+-----+----+-----+------+------+-----+----+----+----+------+ |1 2|89 18|14 9|45 11|287 26|185 23|35 15|1 14|1 15|1 16|247 14| +---+-----+----+-----+------+------+-----+----+----+----+------+
2. Use ". execute after building the full object name in a string
loc=: (,&'_'@[ ,&'_'@, ":@>@]) from=: ".@loc 'PATHSEP' from 'j' \ PATHSEP_j_ \
3. Use ~ invoke or `: invoke gerund, also building the full object name in a string
This last one we will discuss in more detail.
Implementation
The unwritten laws of J style prescribe to chose tacit definitions. Some people believe that brevity also matters. Execute' is frowned upon.
We will define two short tacit conjunctions. One will simply construct a full object name, the other will use evoke over this name.
in_z_=: 2 : 'm ,&(,&''_'') n' NB. build a name fr_z_=: 2 : 'm in n~' NB. evoke a name 'nameA' in 'locA' nameA_locA_
One of the reasons to reserve a separate name for the constructing conjunction is for making assignment:
('nameA' in 'locA')=. i.3 4 $'nameA' fr 'locA'
Here are the examples how our conjunctions are used with nouns.
$'nameA' in 'locA'~ 3 4 +/'nameA' fr 'locA' 12 15 18 21 +/nameA_locA_ 12 15 18 21
Verbs can be produced in a similar manner. Same for adverbs and conjunctions.
Notice how fr is applied over itself: 'fr' from the locale 'base'.
('verbA' in 'locA')=. +/ % # 'verbA' fr 'locA' 'nameA' fr 'locA' 4 5 6 7 verbA_locA_ nameA_locA_ 4 5 6 7 'verbA' 'fr' fr '' 'locA' NB. fr over 'fr' +/ % #
Now we will try to build an application of these conjunctions for examining J namespaces.
We will define another noun in locale 'locA' for demonstration purposes.
[('bb' in 'locA')=. 1;<<"0 i.3 +-+-------+ |1|+-+-+-+| | ||0|1|2|| | |+-+-+-+| +-+-------+
We will need a group of verbs that will retrieve useful information about J names: class, type of noun, shape, level of boxing, size.
cls_z_=: <@({&'nacv?u')@nc typ_z_=: 3 : '''blifc<xr''{~2^.3!:0 y~'&.>`(a:"_)@.(*@nc) shp_z_=: 3 : '$y~'&.>`(a:"_)@.(*@nc) lev_z_=: 3 : 'L.y~'&.>`(a:"_)@.(*@nc) siz_z_=: <@#@(3!:1`(5!:5)@.(*@nc)) (],cls,typ,shp,lev,siz) <'bb_locA_' +--------+-+-+-+-+--+ |bb_locA_|n|<|2|2|52| +--------+-+-+-+-+--+
This is a verb that lists all this information for each name in a given locale.
Notice the use of fr', which iterates over a collection of names in a given locale, returned from nl loc'.
Also defined are two auxiliary verbs for restructuring the result and adding the header.
lspack=: |:`(,:@:(<@:>"1)@:(,@":&.>))@.(*@(*/)@$) lshead=: (;:'name c t shape L size')&,^:(*@(*/)@$) ls=: ''&$: : (4 : 0) NB. y unboxed locale name r=. ,:n=. 'nl' fr y x NB. x same as y for nl r=. r, 'cls' fr y n r=. r, 'typ' fr y n r=. r, 'shp' fr y n r=. r, 'lev' fr y n r=. r, 'siz' fr y n lshead lspack r )
This is how it works. A clone of Unix shell command, suggested by Bjorn Helgason.
ls 'locA' +-----+-+-+-----+-+----+ |name |c|t|shape|L|size| +-----+-+-+-----+-+----+ |bb |n|<|2 |2|44 | |nameA|n|i|3 4 |0|48 | |verbA|v| | | |6 | +-----+-+-+-----+-+----+
This is a generalization of ls to list name classes in all locales, with a tail cutting argument x.
lsall=: 20&$: : (4 : 0) |:>(; <@({.~ x <. #)@":@(y&ls)) &.> nl 6 ) 15 lsall 0 NB. try this one, too +-----------------------+-------------------------------------+---------- |base |j |jcompare ... +-----------------------+-------------------------------------+---------- |+----+-+-+-----+-+----+|+------------------+-+-+-----+-+----+|+------+-+ ||name|c|t|shape|L|size|||name |c|t|shape|L|size|||name |c| |+----+-+-+-----+-+----+|+------------------+-+-+-----+-+----+|+------+-+ ||aa |n|i|3 |0|44 |||BOXES |n|l|3 11 |0|48 |||MAXLCS|n| |+----+-+-+-----+-+----+||BROWSER |n|l|47 |0|48 |||MAXPFX|n| | ||DIRTREEX |n|l|0 |0|52 ||+------+-+ | ||DISPLAYLOAD |n|b| |0|52 || | ||EPSREADER |n|l|49 |0|52 || | ||FORMAT |n|i|6 |0|48 || | ||FORMSIZES |n|i|5 |0|52 || | ||HTTPCMD |n|l|36 |0|48 || | ||IFJIJX |n|b| |0|48 || | ||INPUTLOG |n|<|2 |1|52 || | ||INPUTLOGFILE |n|l|34 |0|56 || | ||LOADED |n|<|4 |1|48 || +-----------------------+-------------------------------------+-----------
Iterating over verbs
You must have noticed the repetition in the body of ls':
r=. r, 'cls' fr y. n r=. r, 'typ' fr y. n r=. r, 'shp' fr y. n r=. r, 'lev' fr y. n r=. r, 'siz' fr y. n
Here comes the issue of iterating over a group of verbs.
The each adverb: &.> allows for its u. verb to iterate over the lists of boxed arguments (y. or x., y.). But there is no such entity that can modify a conjunction to iterate over its arguments (u. and v.).
Since in' is a conjunction already, we turn it into a verb, and modify fr' to include &.> and become a super each'.
Also, since we iterate over verbs, evoke (~) becomes evoke gerund (:).
inV=: 4 : 'x in y' frV=: 2 : '(m inV &.> n)`:0'
And finally, the collection version of the lister shows mapping of a verbs collection over an object argument.
In this simplest case the shape of resulting gerund is linear. However more complex structures are possible and may be justified.
lsc=: ''&$: : (4 : 0) lshead lspack (, cls`typ`shp`lev`siz frV (<y)) 'nl' fr y x )
Here we shall check that everything is still fine, comparing results of the two listers.
0 (ls (;<) lsc)'j' +---------------------------------------------------------------------------+ |+------------------+-+-+-----+-+----+|+------------------+-+-+-----+-+----+| ||name |c|t|shape|L|size|||name |c|t|shape|L|size|| |+------------------+-+-+-----+-+----+|+------------------+-+-+-----+-+----+| ||BOXES |n|l|3 11 |0|48 |||BOXES |n|l|3 11 |0|48 || ||BROWSER |n|l|47 |0|48 |||BROWSER |n|l|47 |0|48 || ||DIRTREEX |n|l|0 |0|52 |||DIRTREEX |n|l|0 |0|52 || ||DISPLAYLOAD |n|b| |0|52 |||DISPLAYLOAD |n|b| |0|52 || ||EPSREADER |n|l|49 |0|52 |||EPSREADER |n|l|49 |0|52 || ||FORMAT |n|i|6 |0|48 |||FORMAT |n|i|6 |0|48 || ||FORMSIZES |n|i|5 |0|52 |||FORMSIZES |n|i|5 |0|52 || ||HTTPCMD |n|l|36 |0|48 |||HTTPCMD |n|l|36 |0|48 || ||IFJIJX |n|b| |0|48 |||IFJIJX |n|b| |0|48 || ||INPUTLOG |n|<|2 |1|52 |||INPUTLOG |n|<|2 |1|52 || ||INPUTLOGFILE |n|l|34 |0|56 |||INPUTLOGFILE |n|l|34 |0|56 || ||LOADED |n|<|4 |1|48 |||LOADED |n|<|4 |1|48 || ||P2UPFONT |n|l|22 |0|52 |||P2UPFONT |n|l|22 |0|52 || ||PATHSEP |n|l| |0|48 |||PATHSEP |n|l| |0|48 || ||PDFREADER |n|l|54 |0|52 |||PDFREADER |n|l|54 |0|52 || ||PRINTERFONT |n|l|16 |0|52 |||PRINTERFONT |n|l|16 |0|52 || ||PRINTOPT |n|l|0 |0|52 |||PRINTOPT |n|l|0 |0|52 || ||PUBLIC |n|<|97 2 |1|48 |||PUBLIC |n|<|97 2 |1|48 || ||SCRIPTS |n|l|45 |0|48 |||SCRIPTS |n|l|45 |0|48 || ||SHOWSIP |n|b| |0|48 |||SHOWSIP |n|b| |0|48 || ||SMPRINT |n|l|5 |0|48 |||SMPRINT |n|l|5 |0|48 || ||SM_CMONITORS |n|i| |0|56 |||SM_CMONITORS |n|i| |0|56 || ||SM_CXVIRTUALSCREEN|n|i| |0|60 |||SM_CXVIRTUALSCREEN|n|i| |0|60 || ||SM_CYVIRTUALSCREEN|n|i| |0|60 |||SM_CYVIRTUALSCREEN|n|i| |0|60 || ||SM_XVIRTUALSCREEN |n|i| |0|60 |||SM_XVIRTUALSCREEN |n|i| |0|60 || ||SM_YVIRTUALSCREEN |n|i| |0|60 |||SM_YVIRTUALSCREEN |n|i| |0|60 || ||SYSTEMFOLDERS |n|<|9 2 |1|56 |||SYSTEMFOLDERS |n|<|9 2 |1|56 || ||TARGET |n|i|0 2 |0|48 |||TARGET |n|i|0 2 |0|48 || ||UNZIP |n|l|34 |0|48 |||UNZIP |n|l|34 |0|48 || ||USERFOLDERS |n|<|11 3 |1|52 |||USERFOLDERS |n|<|11 3 |1|52 || ||WINPOS |n|<|8 2 |1|48 |||WINPOS |n|<|8 2 |1|48 || ||XDIFF |n|l|0 |0|48 |||XDIFF |n|l|0 |0|48 || |+------------------+-+-+-----+-+----+|+------------------+-+-+-----+-+----+| +---------------------------------------------------------------------------+ (ls -: lsc) &> nl 6 1 1 1 1 1 1 1 1 1 1 1 1
And provide another bulk lister in a slightly different scent.
la=: 1 :'>,&.>/(,&":&>/)&.>(<y) (] ,&< u) &.>nl 6' ls la 1 base +----+-+-+-----+-+----+ |name|c|t|shape|L|size| +----+-+-+-----+-+----+ |la |a| | | |46 | +----+-+-+-----+-+----+ j jcompare jfiles jijs jlab jregex +-------+-+-+-----+-+----+ |name |c|t|shape|L|size| +-------+-+-+-----+-+----+ |rxapply|a| | | |171 | |rxcdm |a| | | |23 | |rxmerge|a| | | |55 | +-------+-+-+-----+-+----+ jviewmat jwplot jzgraph locA z +-----------+-+-+-----+-+----+ |name |c|t|shape|L|size| +-----------+-+-+-----+-+----+ |define |a| | | |3 | |each |a| | | |3 | |every |a| | | |2 | |fapplylines|a| | | |409 | |inlocalesx |a| | | |52 | |inv |a| | | |4 | |inverse |a| | | |4 | |items |a| | | |3 | |leaf |a| | | |3 | |rows |a| | | |2 | |rxapply |a| | | |15 | |rxmerge |a| | | |15 | |table |a| | | |62 | +-----------+-+-+-----+-+----+
It is defined as an adverb and allows us to choose the listing verb.
lsc la 2 base +----+-+-+-----+-+----+ |name|c|t|shape|L|size| +----+-+-+-----+-+----+ |frV |c| | | |22 | +----+-+-+-----+-+----+ j jcompare jfiles jijs jlab jregex jviewmat jwplot jzgraph locA z +----+-+-+-----+-+----+ |name|c|t|shape|L|size| +----+-+-+-----+-+----+ |bind|c| | | |13 | |cuts|c| | | |168 | |def |c| | | |2 | |fr |c| | | |13 | |in |c| | | |21 | |on |c| | | |2 | +----+-+-+-----+-+----+