From J Wiki
Jump to navigation Jump to search

A Method for Accessing Multilevel Structures by Name

The fstr adverb can save some typing if you have multilevel structures and use its naming convention for referring to the components. The convention is that the structure items have names of the form strname_fieldname where strname, the structure name, is the same for all items. If a structure item is a box containing another structure, the fieldname for the item should be the same as the strname for the enclosed structure. Without the fstr adverb, a sample reference to a nested structure might be:

}}} but with `fstr` this is shortened to {{{


NB. Adverb.  m. describes an item to be fetched, as
NB. spec[!spec]...[!]
NB.  where spec is
NB.  [prefix?]expr
NB.   where prefix is a character string which (boxed) becomes
NB.     the prefix, or a number, which tells how many trailing
NB.     items of the incoming prefix to keep.  Default is _, meaning
NB.     keep the whole prefix
NB.   and expr is an expression which is evaluated to give a selector.
NB.     This selector (after being boxed) is applied to the input at that
NB.     level.  All '^' and '^:' appearing in the input are replaced by the current
NB.     path, razed with '_' after each item.  If '^:' appears in the
NB.     input, the current path is cleared after all the replacements.
NB.     After that, the path is extended by adding the token following the
NB.     first '^' or '^:', if there is one.
NB.  The specs are processed left-to-right.  When '!' is encountered,
NB.  the result of the selection is unboxed (and subsequent selections are
NB.  applied to each atom after it is unboxed)

NB. x. is one unboxed spec string, y. is incoming path (a list of boxed strings), result is path to use here
inputpath =. ( ({.~ i.&'?') ux_vy ((<@[) ` (0&". ux_vy trailing) @. (*./@(e.&'0123456789')@[)) ) ^:('?'&e.@[)
NB. x. is one unboxed spec string, y. is path to use here, result is path to use at next level
outputpath =. ( ;: ux_vy ( -.@((<'^:')&e.) ux_vy #  ,  ({~ >:@(i.&1)@(e.&((,'^');'^:')))@[ ) ) ^: ('^'&e.@[)
NB. x. is one boxed spec string, y. is (accumulated path[;garbage])
NB. Result is (path for next level;path to use at this level)
accumpath =. ([ (outputpath ,&< ]) inputpath)&>  {.
NB. y. is spec string (boxed in pieces), result is prefix string to use at each level
buildpaths =. ;@:(,&'_'&.>)&.>@:({:"1)@:((accumpath/\.)&.(,&(<0$a:)))&.|.
NB. x. is boxed pieces of the spec string, y. is list of boxed paths
NB. result is x. with substitutions made for ^ and ^:
substpath =. (<;._2@(,&'^')@(#~ -.@(|.!.0)@('^:'&E.))@((}.~ >:@(i.&'?'))^:('?'&e.))@> ux_vy (<@;@}:@,@,.))"0
NB. y. is the spec string, result is selection info, with substitutions
NB. performed (and '!' indicating unboxing)
brktospecs =. (substpath buildpaths) @ (<;.1~ (+. |.!.1)@('!'&=))
NB. y. is the spec string.  Result is
NB. a list of ARs, one for each spec and one for each !
arofspecs =. ('&' arconj&(arverb '{')@arnoun@(".&.>))`((arverb '>')"_) @. ((<,'!')&-:) "0 @: brktospecs
NB. Convert each component to an AR, and then roll up the ARs.  We go from
NB. the right-hand end, but we add each element to the left of the accumulated
NB. AR, so this has the effect of reversing the order and left-grouping the
NB. result
fstrar =: ('@' arconj)~/ @: arofspecs f.
fstr =: 1 : '(fstrar m.)`:6'