Help / JforC / u^:_1, uamp.v, uamp.:v, and u :.v
>> << Pri JfC LJ Phr Dic Voc !: Rel NuVoc wd Help J for C Programmers
19. u^:_1, u&.v, u&.:v, and u :.v
The Obverse u^:_1
What would it mean to apply a verb a negative number of times? Applying a verb _1 times should undo the effect of applying the verb once. In J, u^:n applies the verb u n times, and u^:_1 is defined as the verb that undoes the effect of applying u once. u^:_1 is called the obverse in J, and where possible it is the same as the mathematical inverse of u (or x&u in the dyadic case). Examples:
>: 4 5 >:^:_1 (5) 4
Monad >: adds 1; its obverse subtracts 1.
*&2^:_1 (10) 5
Monad *&2 multiplies by 2; its obverse divides by 2.
2 *^:_1 (10) 5
In the dyadic case, the obverse of x&u is applied. The obverse of 2&* is %&2 .
Not all verbs have obverses; you can see the obverse of a verb v, if there is one, by typing v b. _1 :
+&2 b. _1 -&2 (%&5)@:(+&1) b. _1 -&1@:(5&*) $ b. _1 |domain error
There is no obverse for monad $ .
Some of J's obverses are very ingenious, and you can have a pleasant afternoon experimenting to find them. Most of them are listed in the Dictionary under the ^: conjunction.
Apply Under Transformation: u&.v and u&.:v
Using its ability to apply the obverse of a verb, J provides a feature of great elegance and power with the conjunction u&.v (monadic or dyadic). u&.v (all of whose ranks are the ranks of monad v) executes u after a temporary change in representation given by monad v . Formally, u&.v y is v^:_1@u@v y; informally, x u&.v y is v^:_1 (v x) u (v y) applied to each cell of x and y, with the results collected as usual (we will learn a formal notation for this later). The idea is that you change the operands using the transformation given by v; then do your work with u; then invert the transformation with v^:_1 . Examples:
(<1) +&.> 4;5;6 +-+-+-+ |5|6|7| +-+-+-+
We add x to y; the transformation is that we remove the boxing before we add, and put it back after we finish. The verb +&.> has rank 0 (since monad > has rank 0), so here the scalar x is replicated to the shape of y before the unboxing occurs. fndisplay shows the details, where open' means the inverse of open :
defverbs 'plus"0 open"0' (<1) plus&.open 4;5 +--------------------------+--------------------------+ |open' (open 1) plus open 4|open' (open 1) plus open 5| +--------------------------+--------------------------+
<.&.(10&*) 4 4.43 4.89 4 4.4 4.8
<. y finds the largest integer not greater than y; by temporarily multiplying by 10 we truncate y to the next-lower tenth.
We can easily define a verb to take the arithmetic mean (i. e. the average) of a list:
mean =: monad : '(+/ y) % #y' mean 1 2 4 2.33333
If we want to take the geometric mean, we could define a new verb to multiply and take the root, or we could just take the arithmetic mean of the logarithms and then undo the logarithm:
mean&.(^."_) 1 2 4 2
Note that we had to use a verb of infinite rank as v so that u would be applied to the entire list. This is a common enough pattern that the conjunction &.: is provided which is just like &. but with infinite rank. We could have used mean&.:^. here.
To add 10 minutes to a time represented as hours,minutes,seconds, we can transform to seconds after midnight, do the addition, and transform back:
0 10 0 +&.(24 60 60&#.) 13 55 0 14 5 0
Suppose we had a list of boxed scalar numbers, and we wanted to add them and leave the result boxed. How can we do it?
]a =. <"0 i. 6 +-+-+-+-+-+-+ |0|1|2|3|4|5| +-+-+-+-+-+-+
The easy way is
< +/ > a +--+ |15| +--+
but after you get used to &., you will find that
+/&.:> a +--+ |15| +--+
seems clearer, because it expresses the temporary nature of the unboxing/reboxing. As an exercise, take the time to see why
+&.>/ a
gives the same answer but
+/&.> a
does not.
Defined obverses: u :.v
u :.v has the same ranks as u, and it produces the same result as u, except that the obverse of u :. v is v . By defining verbs with appropriate obverses, you make it possible to use &. and ^:_1 with them. For example, in a finance application it is necessary to deal with dates in both (year,month,day) form and 'market day' form (for example, if Friday is market day number 1200, the following Monday will be market day number 1201). If you have written routines to convert between them:
ymdtomd =: dyad : 'definition' mdtoymd =: dyad : 'definition'
you would be well advised to make them obverses of each other:
ymdtomd =: dyad : 'definition' :. mdtoymd mdtoymd =: dyad : 'definition' :. ymdtomd
so that if you want to find the (y,m,d) date of the next market day after the date ymd, you simply code
1&+&.ymdtomd ymd
and J will convert ymd to a market day, add one, and convert back to (y,m,d) form.
u&:v and u&v
x u&:v y has infinite rank and is the same as (v x) u (v y) . It resembles u&.y but without the application of the obverse. It is just a way of saving a few keystrokes. x u&v y is like x u&:v y except that its ranks are both the same as the rank of monad v . As with @: and @, you are advised to stick to u&:v unless you are sure you need u&v .
The monadic forms u&v y and u&:v y are equivalent to u@v y and u@:v y respectively. I recommend that you use the @ forms rather than the & forms, because your code will be full of m&v and u&n and it will reduce confusion if you don't have unnecessary u&v as well.
In dyadic verbs, x is control and y is data
We noted earlier that usually if a dyad x v y is not symmetric (i. e. if x and y are treated differently), the x operand is the one which is more like control information and the y operand is the one more like data. We can see now that this is a consequence of the definition of x u^:v y : the verb that is applied repeatedly, or the verb whose obverse is taken, is x&u; only the value of y changes between executions of u . When you define dyadic verbs, you should take care to follow the same principle in assigning the left and right operands.
>> << Pri JfC LJ Phr Dic Voc !: Rel NuVoc wd Help J for C Programmers