rslt ← {larg} {''} ##.vof F vof G vof ··· rarg ⍝ Vector of functions.
From Phil Last:
[vof] simulates the distribution of a "vector of functions" among the items of
its argument(s). It can be illustrated by the practical problem: "What is the
size of the rectangle that bounds these three rectangles, with B and C side-by-
side and below A?".
┌──────────────────────────┐
│ A │
│ │
├────────────┬─────────────┴──┐
│ │ │
│ │ C │
│ B │ │
│ │ │
│ ├────────────────┘
│ │
└────────────┘
The answer is:
((1↑⍴A) + (1↑⍴B) ⌈ (1↑⍴C)) , (¯1↑⍴A) ⌈ (¯1↑⍴B) + (¯1↑⍴C)
but it would be much nicer to be able to say:
(⍴A) (+⌈) (⍴B) (⌈+) (⍴C)
A diagram shows the distribution of functions with respect to argument items:
┌─────┬────────┬─────┬────────┐
│ │ │ │ │
(⍴A)[0 1] (+⌈) (⍴B)[0 1] (⌈+) (⍴C)[0 1]
│ │ │ │ │
└────┴─────────┴────┴─────────┘
where (+⌈) and (⌈+) are both 2-item "function vectors" to be distributed over
their 2-item argument(s). Compare this with the way that a vector of namespace
references in a function expression, distributes its function over its arguments
without needing to specify each:
(ref0 ref1 ref2 ref3).{···w} ⍳4
More generally:
a b c···(f g h···) x y z··· ←→ (a f x)(b g y)(c h z)··· ⍝ vector vector
(⊂a) (f g h···) x y z··· ←→ (a f x)(a g y)(a h z)··· ⍝ scalar vector
a b c···(f g h···) ⊂x ←→ (a f x)(b g x)(c h x)··· ⍝ vector scalar
(⊂a) (f g h···) ⊂x ←→ (a f x)(a g x)(a h x)··· ⍝ scalar scalar
(f g h···) x y z··· ←→ (f x)(g y)(h z)··· ⍝ monadic vector
(f g h···) ⊂x ←→ (f x)(g x)(h x)··· ⍝ monadic scalar
[vof] implements the distributive function vector in the alternating mode we
have seen with →of←, →case← and →lof←.
{a b c ···} {''} vof f vof g vof h ··· x y z
As with →lof← we need (except in special circumstances) the closing call with
the null function. An alternative would be to provide a slightly different
"special" coding for the leftmost operator:
_vof←{ ⍝ Close vector of functions.
⍺←⊂ ⍝ ⍺ elided: ⊂⍵.
(al ar)(wl wr)←⍺ ⍵ ⍝ distrubute arg(s).
1≡⍺ 1:(⍺⍺ wl)(⍵⍵ wr) ⍝ mondadic.
(al ⍺⍺ wl)(ar ⍵⍵ wr) ⍝ dyadic.
}
Although more expensive, the following coding works without a terminator to the
left. The control over the iteration is the length of the data so if the number
of functions is different it goes wrong as do the others.
Uses the same method of self reference as the coding of fk in →fork←:
vof←{
(M D)←112358314594370 774156178538190
⍺←M
(m d)←M D∊⊂⍺
e←2∊⍴⍵
e<m:(M ⍺⍺ ¯1↓⍵),⊂⍵⍵⊃⊢/⍵
e<d:(D ⍺⍺ ¯1↓⍵),⍵⍵/⊃⊢/⍵
e∧m:⊃⍺⍺{(⍺⍺ ⍺)(⍵⍵ ⍵)}⍵⍵/⍵
e∧d:⊃⍺⍺{(⍺⍺/⍺),⍵⍵/⍵}⍵⍵/⍵
D ∇ ⍺{⍺ ⍵}¨⍵
}
Examples:
1 2 3 4 {''} vof + vof ! vof ? vof | 5 6 7 8 ⍝ vector vector
6 15 1 6 4 0
4 {''} vof + vof ! vof ? vof | 5 6 7 8 ⍝ scalar vector
9 15 4 2 1 5 0
1 2 3 4 {''} vof + vof ! vof ? vof | 5 ⍝ vector scalar
6 10 4 5 2 1
4 {''} vof + vof ! vof ? vof | 5 ⍝ scalar scalar
9 5 3 5 1 4 1
{''} vof + vof ! vof ? vof | 5 6 7 8 ⍝ monadic vector
5 720 1 8
{''} vof + vof ! vof ? vof | 5 ⍝ monadic scalar
5 120 2 5
{2⍴⍵} vof {3⍴⍵} vof {4⍴⍵} 2 3 4 ⍝ without left closure
┌─┬─┬─────┬───────┐
│2│2│3 3 3│4 4 4 4│
└─┴─┴─────┴───────┘
{⍬} vof {2⍴⍵} vof {3⍴⍵} vof {4⍴⍵} 2 3 4 ⍝ explicit left closure
┌───┬─────┬───────┐
│2 2│3 3 3│4 4 4 4│
└───┴─────┴───────┘
{2⍴⍵} _vof {3⍴⍵} vof {4⍴⍵} 2 3 4 ⍝ closure using [_vof]
┌───┬─────┬───────┐
│2 2│3 3 3│4 4 4 4│
└───┴─────┴───────┘
Notice that the length of the result is the number of functions, not necessarily
the length of the argument(s).
See also: case of lof Function_arrays co_ops
Back to: contents
Back to: Workspaces