───────────────
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