Vocabulary/coa

From J Wiki
Jump to navigation Jump to search

>> <<   Back to: Vocabulary Thru to: Dictionary

3 : n 4 : n Explicit Verb Definition Conjunction

Rank Infinity -- operates on x and y as a whole -- WHY IS THIS IMPORTANT?



Defines an explicit verb.

Information.png Conjunction Def (:) has several different uses, requiring several pages to document it

The word: define is a synonym for  : 0
  Thus the word: define hides an occurrence of  m : n

  • Operand m tells what type of verb it is
    • one of the special values 3 or 4, or their synonyms: verb (=3), monad (=3), or dyad (=4).
  • Operand n specifies the J code which J uses to define the verb.
    • If n is a character string — it must be valid J code and will become the body of a (one-line) verb.
    • If n is the special value 0 — this signals to J that a multiline body starts with the line immediately below the  m : n line.
      • and ends with the line consisting of a single: )

It follows that the phrase:

  •  verb define is equivalent to  3 : 0
  •  monad define is equivalent to  3 : 0 also
  •  dyad define is equivalent to  4 : 0

These forms are what you usually see in the code of expert J-ers.

When J executes the phrase:  m : n — it creates the verb then-and-there.

  • The verb thus created is anonymous, i.e. it is simply a value.
  • But typically this (verb) value is straightaway assigned to a name, e.g. covar (as in the worked example below).
m Type of verb n Type of body
3 monad, or dual-valence string one-liner
4 dyad only 0 multiline body follows immediately

Example:

The following table is the anatomy of a sample explicit verb named: covar

Notes Code
0 NB. Calculate covariance of two lists

NB. x and y are the lists
NB. If x is omitted, y is used, giving variance of y
NB. Calculates mean of each first, then finds average of the product of deviations
NB. Result is covariance (atom)

2, 1 covar =: verb define
3 NB. monad: take covariance of y with itself
11 qprintf 'y '
4, 12 y covar y
5 :
6, 7, 4 if. 0 = #y do.
  smoutput 'empty covariance'
12, 7   0 return.
7 end.
9, 8 sumx =. +/ x
9, 8 meanx =. sumx % (#x)
9, 4 meany =. (+/ y) % #y
10 DMEANY =: meany NB. debug
11 qprintf 'meanx meany ' NB. debug
12 (+/ (x-meanx)*(y-meany)) % #x
13 )

{i} Download a J script of the definition of covar: File:Covar.ijs

Notes:

0. The verb definition itself is preceded by a prologue describing the arguments it needs, and the result it computes.

  • This is a convention among J-ers and is not essential for this example to work.

1. The phrase  verb define starts the definition of the verb. (This line is loosely called the header)

  • define (or its equivalent:  :0 ) says that the body of the verb consists of all lines below this one, down to the line consisting of the single word:
)

2. The verb created by  verb define is assigned to the name covar

  • The assignment uses =: which makes it public, i.e. the name covar will be available for use outside the script it was defined in.
    • Use =. instead of =: to define a verb that goes away once it has served its purpose within the script, i.e. while the script is actually loading.
    • WARNING: Be careful not to use =. by mistake within a script when you mean =: (...or you might spend hours trying to find out where your verb has gone!)

3. The first section of the body defines the monadic valence of the verb.

  • Execution of covar monadically starts with the first line of this section.

4. When you run covar (either monadically or dyadically), the value of the right-hand argument to covar gets privately assigned to the name y.

  • You can re-assign y privately, but the new value does not leak outside the verb, i.e. it stays confined inside the verb's namespace, and disappears along with the namespace when the verb terminates.

5. The valence separator is the line containing the single word:

:
  • It is meant to resemble the conjunction: Monad-Dyad (:) — (although inside a verb definition body it doesn't actually run this primitive.)
  • The lines above the valence separator are the monadic section of the body
  • The lines below the valence separator are the dyadic section of the body.

6. Execution of covar dyadically starts with the first line of the dyadic section.

7. Control structures such as if./do./else./end. and do./while./end. can change the order in which sentences are executed, or (as here) whether they're executed at all.

8. When you run covar dyadically, the value of the left-hand argument to the verb gets privately assigned to the name x.

  • What Note 4 (above) says about y applies to x too.

9. Any name assigned using =. is a private assignment.

  • A name so defined is not visible outside the body of the explicit verb — it stays confined inside the verb's namespace, which disappears when the verb terminates.

10. Assignment using =: is public and the name is visible from inside any other verb (in the same locale).

  • This feature is typically used when debugging, where it can be very handy. For example, try putting this sentence inside the body:  y_z_ =: y
  • But it is poor practise to design your code to rely on =: , since it leads to verbs "feeling inside each others' guts", whether or not you mean them to.
  • A user's trick: the extra spaces before the =: indicate that this is a debugging assignment. Subsequent search for =: preceded by two spaces will find all debugging assignments.

11. qprintf is another useful debugging tool. It is part of the printf addon.
   To make sure it's available, you need to have executed:

require 'format/printf'

12. The result of the last line executed by the verb becomes the result returned by the verb.

  • This result doesn't need to be assigned to a name. It just "drops out the bottom".
    • This happens whether you want it to or not.
      • Some verbs aren't designed to return a useful result.
      • In practice that rarely does any harm. That is, unless the last value you assign is not a noun but a verb (whereupon J puzzlingly signals  syntax error ).
      • But if you really don't want to see the result that drops out (e.g. it's not a noun), try having  empty'' or  i.0 0 as the last line of your definition.
  • A good safety end-stop, and a clear indication that the verb is not meant to return a result for anyone to use.
  • NOTE: the last line executed is not always the last line of the body.
    • Use the control word return. to return precisely the value you want to be the verb's result.

13. A line containing the single word: ) is the body delimiter.

  • The body consists of all the lines above it, up to the  m : n line (loosely called the header).
  • The body does not include the body delimiter. Nor does it include the header either.

Sample execution:

   covar 1 2 3 4 5
y=1 2 3 4 5
meanx=3 meany=3
2
   DMEANY          NB. This name has been assigned using (=:) - so it's still there.
3
   sumx            NB. This name has been assigned using (=.) - so it disappears when covar stops running.
|value error: sumx

Running the verb monadically (i.e. with a y-argument but no x-argument) starts in the monadic valence section. This prints y and then calls the dyadic valence section.

The dyadic valence section prints meanx and meany . Then it terminates with the result 2.

The "debug" noun DMEANY persists after the verb has terminated, but all the names (e.g. sumx) assigned by private assignment disappear again

or, if they existed before, they revert to their former values

   5 4 3 2 1 covar 1 2 3 4 5
meanx=3 meany=3
_2

Running the verb dyadically (i.e. with both an x-argument and a y-argument) starts in the dyadic valence section.


Details

  • covar =: verb define
    • If there's no valence separator (:) in the body, only the monadic valence gets defined.
    • If you then call covar with an x-argument, J will signal  domain error
  • covar =: monad define
    • The same thing happens (because both monad and verb are synonyms for the number 3)
  • mydyad =: dyad define
    • Only the dyadic valence gets defined.
    • If you then call mydyad monadically, i.e. without an x-argument, J will signal  domain error .