R∆ ← L (index ##.merge '∘' ) R              ⍝ Suggestion for a merge operator.
R∆ ← L (index ##.merge axes) R              ⍝ right operand specifies axes,
R∆ ← L (selfn ##.merge '∘' ) R              ⍝ left operand can be selection fn.

[merge] has two cases:

With an array left operand:
        ¯¯¯¯¯
    ⍺(⍺⍺ merge'∘'  )⍵  → (⍺⍺⌷⍵)←⍺ ⋄ ⍵

    ⍺(⍺⍺ merge axis)⍵  → (⍺⍺⌷[axis]⍵)←⍺ ⋄ ⍵

With a function left operand:
       ¯¯¯¯¯¯¯¯
    ⍺(⍺⍺ merge'∘')⍵  →  ((,⍺ ⍺⍺ ⍵)/,⍵)←⍺ ⋄ ⍵

Note that,  from  Dyalog  V13.0, index function ⌷ can take a short left argument
vector. This feature is passed along to [merge].

Classic APL lacks a general, non-procedural way to express the "triadic"  funct-
ion: "THIS array but with THOSE items at THESE positions". For example: the let-
ters of the alphabet but with stars instead of vowels.

Rather, it encourages us to use a 3-stage procedure and to supply a name for the
subject array:

    [1] Name the subject array,                             ⍝ THIS ← ⍵
    [2] Update the array, using its name,                   ⍝ THIS[THESE]←THOSE
    [3] Dereference the name for the result.                ⍝ THIS

(muse:

    Ideally, the language should never force us into naming the results of expr-
    essions. Better that we choose to name things only in order to create mental
    abstractions that are easier for us to work with. For example, the following
    three code fragments are equivalent and each reducible by the language eval-
    uator to the syntax tree on the right:

    (+/⍵)÷⍴⍵                                    ⍝
                                                ⍝        ┌───┼─┐
    sum←+/⍵ ⋄ num←⍴⍵  ⋄ sum÷num                 ⍝        ├─┐ ÷ ├─┐
                                                ⍝      ┌─┤ ⍵   ⍴ ⍵
    sum←+/ ⋄ num←⍴ ⋄ (sum ⍵)÷num ⍵              ⍝      + /

    Sound bite: "Names allow us to chop up our programs into mind-sized pieces."
)

(muse:

    If  [merge]  were to be implemented as a primitive operator, the "axis case"
    would use APL's regular axis operator and [merge] itself would  be  monadic.
    For example, suppose we chose "→" as the symbol for merge, then we might see
    expressions such as these:

        ⍺(v→)⍵          ⍝ with all axes selected: (⍴v)≡⍴⍴⍵.

        ⍺(v→[1 0])⍵     ⍝ with explicit axes: 2=⍴v.

        ⍺ {...⍵}→ ⍵     ⍝ with boolean-returning selection function.
)

Larg vs Rarg
------------
With indexed assignment, the "old" array is on the left and the "new" values are
on the right:

    OLD[⍳3]←'NEW'

We save on parentheses if we arrange for the value that would, more  often  than
not be named or literal, to occur on the left. Here are examples of both cases:

    MAT (... merge) lcase MAT   ⍝ Lower-casification of selected chars in MAT.
⍝   old (sel merge) new         ⍝ say: "Old with sel[ected items] set to new".
vs:                               ¯¯¯¯
    '*' (... merge) 5 5⍴⎕A      ⍝ Stars for selected chars in matrix.
⍝   new (sel merge) old         ⍝ say: "New for sel[ection] in old".
                                  ¯¯¯¯
Arguably more important than saving parentheses, is the impact of argument order
on the notation as tool-of-thought. It seems (to JMS) to be less distracting  if
the modification (new value) is on the left; merges are applied  as  refinements
to the result of the expression developed on the right. Further:

- Functional programming uses a  notation:  [new/old]expr "new for old in expr",
  where "new" and "old" are strings. "old" specifies positions of matches within
  "expr". [merge]'s left operand is simply a generalisation: [new/expr∊old]expr.

- Looking at the vocalisation (say:) above, the first seems more procedural  and
  the second more declarative. Declarative is, in general, easier on the mind.

- It is more convenient if the ambi-valent  selection  function  takes  the  old
  array as right argument (and so less confusing if this is also the right argu-
  ment of the derived function as a whole). See examples below.

NB: A selection _function_ as operand may specify a non-rectanglar subset of the
items of the subject array.  In this case, the items of a non-single right argu-
ment vector populate the selection in ravel order.

    A[(,⍺⍺ ⍵)/,⍳⍴A←⍵]←⍺

As in the above code,  LENGTH ERROR  will be generated unless ⍺ is a single-item
array or is vector with the same number of items as the selection.

(muse:

    To select a single item in a rank-⍵ array, we need an ⍵-vector.  Dyalog  im-
    plements three forms of indexing: "simple", "choose" and "reach".

    Simple indexing (v⍴...)[x;y;...] uses a "v-tuple" of arrays, whose cartesian
    product provides the array of v-vectors that selects a rectangular slice  of
    the subject array.  The shape of the result is the shape  of  the  cartesian
    product.

    Choose indexing (v⍴...)[x y ...] uses an array of v-vectors,  each  item  of
    which selects  directly  from the subject array.  The shape of the result is
    the shape of the selection array.

    Simple and choose indexing converge in the case where the subject array is a
    vector.

    Reach indexing (u⍴⊂v⍴⊂...)[x y ...] uses an array of vector  "paths",  where
    each path is a vector of (u v ..)-vectors, each item of  which  selects into
    items of items of the subject array. The shape of the result is the shape of
    the selection array.

    [merge] addresses the simple and choose cases with its  array  and  function
    operands, respectively.  It does not help directly with the equivalent reach
    indexing.
)

Examples:

    vec←11 to 19                    ⍝ vector of numbers.

    vec
11 12 13 14 15 16 17 18 19

    0 (2∘| merge'∘') vec            ⍝ function operand: with zeros for odd nums.
0 12 0 14 0 16 0 18 0

    'x' ({1=?9⍴2} merge'∘') vec     ⍝ random merge of 'x'
x 12 x 14 xx 17 18 19

    0 (4 merge'∘') vec              ⍝ 4th item replaced with 0.
11 12 13 0 15 16 17 18 19

    0 ((⊂3 4 5) merge'∘') vec       ⍝ 3rd-5th items replaced with 0s.
11 12 0 0 0 16 17 18 19

    1 2 3 ((⊂4 3 2) merge'∘') vec   ⍝ 4th-2nd items replaced with 1-3.
11 3 2 1 15 16 17 18 19

    mat←10⊥¨⍳4 5                    ⍝ matrix of numbers.

    mat
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45

    0({0=3|⍵}merge'∘')mat           ⍝ function operand: every 3rd item replaced.
11  0 13 14  0
 0 22 23  0 25
31 32  0 34 35
41  0 43 44  0

    3 ({0=⍺|⍵}merge'∘')mat          ⍝ dyadic operand: every ⍺th item replaced.
11  3 13 14  3
 3 22 23  3 25
31 32  3 34 35
41  3 43 44  3

    0 (2 merge 1) mat               ⍝ 2nd row replaced with 0s.
11 12 13 14 15
 0  0  0  0  0
31 32 33 34 35
41 42 43 44 45

    0 (4 merge 2) mat               ⍝ 4th col replaced with 0s.
11 12 13 0 15
21 22 23 0 25
31 32 33 0 35
41 42 43 0 45

    0 ((⊂2 3)merge 1) mat           ⍝ 2nd & 3rd rows replaced with 0s.
11 12 13 14 15
 0  0  0  0  0
 0  0  0  0  0
41 42 43 44 45

    (2 5⍴⍳10) ((⊂3 2)merge 1) mat   ⍝ 3rd & 2nd rows replaced with numbers.
11 12 13 14 15
 6  7  8  9 10
 1  2  3  4  5
41 42 43 44 45

    0 ((2 3)(2 4)merge'∘') mat      ⍝ 2nd 3rd rows, 2nd 4th cols ← 0.
11 12 13 14 15
21  0 23  0 25
31  0 33  0 35
41 42 43 44 45

    (2 2⍴⍳4) ((2 3)(2 4)merge'∘') mat   ⍝   ..      ..      numbers.
11 12 13 14 15
21  1 23  2 25
31  3 33  4 35
41 42 43 44 45

    cube←10⊥¨⍳2 3 4                 ⍝ cuboid of numbers.

    cube
111 112 113 114
121 122 123 124
131 132 133 134

211 212 213 214
221 222 223 224
231 232 233 234

    0 (2 merge 1) cube              ⍝ 2nd plane replaced with 0s.
111 112 113 114
121 122 123 124
131 132 133 134

  0   0   0   0
  0   0   0   0
  0   0   0   0

    0 (2 merge 2) cube              ⍝ 2nd rows replaced with 0.
111 112 113 114
  0   0   0   0
131 132 133 134

211 212 213 214
  0   0   0   0
231 232 233 234

    0 (2 merge 3) cube              ⍝ 2nd cols replaced with 0s.
111 0 113 114
121 0 123 124
131 0 133 134

211 0 213 214
221 0 223 224
231 0 233 234

    (3 4⍴⍳12) (2 merge 1) cube      ⍝ 2nd plane replaced with matrix.
111 112 113 114
121 122 123 124
131 132 133 134

  1   2   3   4
  5   6   7   8
  9  10  11  12

    (⍳3) (2 1 merge 1 3) cube       ⍝ 2nd row, 1st col replaced with vector.
111 112 113 114
121 122 123 124
131 132 133 134

  1 212 213 214
  2 222 223 224
  3 232 233 234

    99 (⍬ merge '∘') 88             ⍝ scalar case.
99

⍝ Here's a handy derived function:

    atfirst ← ⎕io merge ⎕io         ⍝ merge with first row (plane, ...).

    '⍟' atfirst 4⍴⎕a                ⍝ first item of vector.
⍟BCD

    'this' atfirst 3 4⍴⎕a           ⍝ first row of matrix.
this
EFGH
IJKL

    '⎕' atfirst 2 3 4⍴⎕a            ⍝ first plane of cube.
⎕⎕⎕⎕
⎕⎕⎕⎕
⎕⎕⎕⎕

MNOP
QRST
UVWX

See also: squad select

Back to: contents

Back to: Workspaces

Trouble seeing APL font?