Adverbs and Conjunctions
An Implementation of J



An adverb is monadic, applying to a noun or verb argument on its left; a conjunction is dyadic, applying to noun or verb arguments on its left and right. The result is usually a verb, but can also be a noun, adverb, or conjunction.

The conjunction & is used here to illustrate the relationship between relevant system components. (The implementation of adverbs is similar.) & derives a verb depending on whether the arguments are nouns (m and n) or verbs (u and v):

   m&n       gerund join
   m&v       m&v y is m v y
   u&n       u&n y is y v n
   u&v       u&v y is u v y;   x u&v y is (v x) u (v y)
A verb defined from & is (internally) an array of type VERB whose value is interpreted according to the defined type V in file jtype.h:

   typedef struct {AF f1,f2;A f,g,h;I flag,mr,lr,rr;C id;} V;
     f1     monad
f2 dyad
f left conjunction argument or adverb argument
g right conjunction argument
h auxiliary argument
flag bit flags
mr monadic rank
lr left rank
rr right rank
id ID byte

If fn=: %.&|:, the arrays would be:

         k   flag    m     t     c     n     r
      ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬
   fn │   28│    0│    8│ VERB│    3│    1│    0│...
      └─────┴─────┴─────┴─────┴─────┴─────┴─────┴
            ┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
         ...│  on1│  on2│   %.│   |:│    0│    0│    _│    _│    _│&    │
            ┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
               f1    f2    f     g     h   flag    mr    lr    rr   id

         k   flag    m     t     c     n     r
      ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬
   %. │   28│    0│    8│ VERB│    _│    1│    0│...
      └─────┴─────┴─────┴─────┴─────┴─────┴─────┴
            ┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
         ...│ minv│ mdiv│    0│    0│    0│    0│    2│    _│    2│%.   │
            ┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
               f1    f2    f     g     h   flag    mr    lr    rr   id

         k   flag    m     t     c     n     r
      ┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬
   |: │   28│    0│    8│ VERB│    _│    1│    0│...
      └─────┴─────┴─────┴─────┴─────┴─────┴─────┴
            ┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
         ...│cant1│cant2│    0│    0│    0│    0│    _│    1│    _│|:   │
            ┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
               f1    f2    f     g     h   flag    mr    lr    rr   id
Access to the parts of fn is by name and by macros defined in files jt.h and a.h, and never by offsets and indices. Thus AV(fn) points to the value part of fn. And if sv=(V*)AV(fn), then sv->f1 is on1; sv->f2 is on2; sv->f is the array for %.; sv->g is the array for |: (that is, sv->f and sv->g are arrays similar to fn); sv->mr is _ (indicating that fn has infinite monadic rank); and so on. The macro VAV(f), defined as ((V*)AV(f)), is useful for working with adverbs and conjunctions.

To introduce & into the system, functions which implement & are added to file c.c (or one of the c*.c files), and declarations of global objects are added to file je.h:
File c.c:
   static CS1(on1,  CALL2(f1,CALL2(g1,w,gs),fs))
   static CS2(on2,  CALL3(f2,CALL2(g1,a,gs),CALL2(g1,w,gs),fs))

   static DF1(withl){DECLFG; R jt->rank?irs2(fs,w,gs,AR(fs),jt->rank[1],g2):CALL3(g2,fs,w,gs);}
   static DF1(withr){DECLFG; R jt->rank?irs2(w,gs,fs,jt->rank[1],AR(gs),f2):CALL3(f2,w,gs,fs);}

   F2(jtamp){I m;
    RZ(a&&w);
    switch(CONJCASE(a,w)){
     default: ASSERTSYS(0,"amp");
     case NN: R gjoin(CAMP,a,w);
     case NV: R CDERIV(CAMP,withl,0L,RMAX,RMAX,RMAX);
     case VN: R CDERIV(CAMP,withr,0L,RMAX,RMAX,RMAX);
     case VV: m=mr(w); R CDERIV(CAMP,ID(a)==CSLASH&&ID(w)==CCOMMA?jtredravel:on1,on2,m,m,m);
   }}

File je.h:
   extern F2(jtamp);
Corresponding to the four possibilities, amp defines four cases. (The impossible default case is to obviate a spurious C compiler warning.) The functions withl, withr, on1, and on2 are applied when a verb derived from & is applied. The VV case also recognizes u/&, as a special case, whereby redravel is applied instead of on1.

For the example in question, %.&|: m=: ?4 4$100 first branches to the case VV in amp, and subsequently applies on1 to m. Consider a partial macro expansion of on1 and the values of its local variables:

Macro Expansion:
   static A on1(J jt,A w,A self){PROLOG;V*sv=VAV(self);
    A fs=sv->f;AF f1=fs?VAV(fs)->f1:0,f2=fs?VAV(fs)->f2:0;
    A gs=sv->g;AF g1=gs?VAV(gs)->f1:0,g2=gs?VAV(gs)->f2:0; A z;
    PREF1(on1); 
    z=f1(jt,g1(jt,w,gs),fs);
    EPILOG(z);
   }
Local Variables:
     w        the matrix m
self the verb fn
sv pointer to the value part of fn as an array
fs left argument to &, that is %.
f1 monad of %.
f2 dyad of %.
gs right argument to &, that is |:
g1 monad of |:
g2 dyad of |:

The initialization of sv, fs, f1, and so on are the same for all adverbs and conjunctions; the details of such initialization are normally suppressed by the use of macros. If an argument to & (i.e. fs or gs) is itself a result of adverbs and conjunctions, expressions such as g1(jt,w,gs) or f1(jt,xxx,gs) engender further executions as occurs in on1. The macro PREF1 implements rank, and the macros PROLOG and EPILOG manage memory.

The association between & and amp is established in the table pst in file t.c, exactly the way such associations are done for verbs. In particular, CAMP is the ID for & and ds(CAMP) is & as an array (that is, ds(CAMP) is &).

The utilities df1 and df2 in file au.c apply the monad or the dyad of a verb. For example:

     ds(CPOUND) #
ds(COPE) >
amp(ds(CPOUND),ds(COPE)) #&>
 
df1(w,ds(CPOUND)) # w
df1(  w,amp(ds(CPOUND),ds(COPE))) #&> w
df2(a,w,amp(ds(CPOUND),ds(COPE)))    a #&> w



NextPreviousIndexTable of Contents