─────────────── Function Arrays ─────────────── Dyalog APL doesn't have arrays of functions but they can be simulated in various ways. Apart from →fnarray←, each of the operators here utilises a derived funct- ion "tree". The seemingly "linear" sequence ··· F op G op H ··· arg, can be rep- resented graphically in the following fashion: ┌─··· arg ┌─op─┐ ┌─op─┐ H ┌─op─┐ G ··· F The function array operators typically traverse the left "spine" of the tree by applying ⍺⍺ to an argument until the required operand is reached. →fnarray← uses an array of namespace references to contain each function. ------------------ Function selectors ------------------ Operators →case← and →of← apply the selected monadic function to the right argu- ment of the derived function. →case← uses a boolean "mask" and →of←, a "pick" index. There is a subtle but significant difference in the usage of →case← and →of←: 0 1 0 - case ! case + 3 ⍝ [larg] fn case fn case fn rarg 6 2 of - of ! of + 3 ⍝ [land] of fn of fn of fn rarg 6 [larg] is the left _argument_ of the derived function: (fn case fn case fn), whereas [land] is the left _operand_ of the leftmost →of← operator. In Dyalog, we can _name_ a derived function such as (fn case fn case fn) and with this example, sometime later use the name in conjunction with a left argu- ment to "pick" a function to apply to a right argument. However, we can't name an incomplete operator expression (of fn of fn of fn) that has a missing left operand. Operationally, →case← can "see" its left argument from the top (righmost) node of the derived function tree and pass an optionally modified copy of it left- wards to each lower level. An →of←-tree on the other hand, has no left argument and must traverse left until it happens upon an operand that isn't a function. Phil Last suggests a further operator [sel], which indexes _leftwards_ from the rightmost operand function: sel←{ ⍝ select function from RHS of list. ⍺≤⎕IO:⍵⍵ ⍵ ⍝ apply ⍵⍵ at selected level. (⍺-1)⍺⍺ ⍵ ⍝ traverse left. } This combines →of←'s simplicity in that a pick index is used, with the advantage of →case←, that the derived function may be named. But here's the rub: the left- most operand function must accept but ignore, a left argument. This is because the operator doesn't know it _is_ the leftmost function and so passes the next lowest index as left argument. This is not really a problem as an ambivalent function may easily be made strictly monadic by composing or enclosing it with a monadic identity function: ⊢∘fn or {fn ⍵}. fnlist←{⌈⍵} sel ⌊ sel - sel ÷ ⍝ 'vector' of functions, ⎕nc'fnlist' ⍝ ... is a derived function. 3 1 fnlist 2.5 ⍝ 1st from right function. 0.4 4 fnlist 2.5 ⍝ 4th from right function. 3 --------------------- Function distributors --------------------- Operators →lof← (list-of-functions) and →vof← (vector-of-functions) distribute their functions over or between their array arguments. The distinction between →lof← and →vof← is that in the former, each function is applied to the whole argument array, whereas in the latter, the items of the argument are distributed to each function. monadic: F lof G x y ←→ (F x y) (G x y) F vof G x y ←→ (F x ) (G y) dyadic: a b F lof G x y ←→ (a b F x y) (a b G x y) a b F vof G x y ←→ (a F x ) ( b G y) Examples: 1 5 3 + lof ⌈ lof ⌊ lof | 6 2 4 7 7 7 6 5 4 1 2 3 0 2 1 1 5 3 + vof ⌈ vof ⌊ vof | 6 2 4 6 2 1 - lof ÷ lof ! 4 5 6 ¯4 ¯5 ¯6 0.25 0.2 0.1666666667 24 120 720 - vof ÷ vof ! 4 5 6 ¯4 0.2 720 See also: case of lof vof for fnarray Back to: contents Back to: Workspaces