Function Trains

Introduction

A Train is a sequence of 2 or 3 functions, or an array followed by two functions, which bind together to form a function.

Forks and Atops

The following trains are currently supported where f, g and h are functions and A is an array:

`      f g h      A g h        g h`

The 3-item trains (f g h) and (A g h) are termed forks while the 2-item train (g h) is termed an atop. To distinguish the two styles of fork, we can use the terms fgh-fork or Agh-fork.

Trains as Functions

A train is syntactically equivalent to a function and so, in common with any other function, may be:

• named using assignment
• applied to or between arguments
• consumed by operators as an operand
• and so forth.

In particular, trains may be applied to a single array (monadic use) or between 2 arrays (dyadic use), providing six new constructs.

```    ⍺(f g h)⍵ ←→ (⍺ f ⍵) g (⍺ h ⍵)   ⍝ dyadic (fgh) fork
⍺(A g h)⍵ ←→    A    g (⍺ h ⍵)   ⍝ dyadic (Agh) fork
⍺(  g h)⍵ ←→         g (⍺ h ⍵)   ⍝ dyadic       atop

(f g h)⍵ ←→ (  f ⍵) g (  h ⍵)   ⍝ monadic (fgh) fork
(A g h)⍵ ←→    A    g (  h ⍵)   ⍝ monadic (Agh) fork
(  g h)⍵ ←→         g (  h ⍵)   ⍝ monadic       atop```

Identifying a Train

For a sequence to be interpreted as a train it must be separated from the argument to which it is applied. This can be done using parentheses or by naming the derived function.

Example - fork: negation of catenated with reciprocal

```      (-,÷)5
¯5 0.2```

Example - named fork

```      negrec←-,÷
negrec 5
¯5 0.2```

Whereas, without these means to identify the sequence as a train, the expression:

```      -,÷ 5
¯0.2```

means the negation of the ravel of the reciprocal of 5.

Idiom Recognition

Function trains lend themselves to idiom recognition, a technique used to optimise the performance of certain expressions.

Example

An expression to find the first position in a random integer vector X of a number greater than 999000 is:

```      X←?1e6⍴1e6
(X≥999000)⍳1
1704```

A function train is not only more concise, it is faster too.

```      X (⍳∘1 ≥) 999000
1704```

Trains of Trains

As a train resolves to a function, a sequences of more than 3 functions represents a train of trains. Function sequences longer than 3 are bound in threes, starting from the right:

`... fu fv fw fx fy fz → ... fu (fv fw (fx fy fz))`

This means that, in the absence of parentheses, a sequence of an odd number of functions resolves to a 3-train (fork) and an even-numbered sequence resolves to a 2-train (atop):

`e f g h i j k → e f(g h(i j k))     ⍝ fork(fork(fork))f g h i j k →   f(g h(i j k))       ⍝ atop(fork(fork))`

Examples

```      6( +,-,×,÷)2     ⍝ fork:(6+2),((6-2),((6×2),(6÷2)))
8 4 12 3

6(⌽+,-,×,÷)2     ⍝ atop: ⌽ (6+2), ...
3 12 4 8

]boxing on
Was OFF```
```      +,-,×,÷          ⍝ boxed display of fork
┌─┬─┬─────────────┐
│+│,│┌─┬─┬───────┐│
│ │ ││-│,│┌─┬─┬─┐││
│ │ ││ │ ││×│,│÷│││
│ │ ││ │ │└─┴─┴─┘││
│ │ │└─┴─┴───────┘│
└─┴─┴─────────────┘
⌽+,-,×,÷         ⍝ boxed display of atop
┌─┬───────────────────┐
│⌽│┌─┬─┬─────────────┐│
│ ││+│,│┌─┬─┬───────┐││
│ ││ │ ││-│,│┌─┬─┬─┐│││
│ ││ │ ││ │ ││×│,│÷││││
│ ││ │ ││ │ │└─┴─┴─┘│││
│ ││ │ │└─┴─┴───────┘││
│ │└─┴─┴─────────────┘│
└─┴───────────────────┘```
```      ]boxing -trains=tree
Was -trains=box
+,-,×,÷          ⍝ boxed (tree) display of fork
┌─┼───┐
+ , ┌─┼───┐
- , ┌─┼─┐
× , ÷
```

Binding Strengths

The binding strength between the items of a train is less than that of operand-operator binding. In other words, operators bind first with their function (or array) operands to form derived functions, which may then participate as items in a train.

Example:

```      +⌿ ÷ ≢            ⍝ fork for mean value
┌─────┬─┬─┐
│┌─┬─┐│÷│≢│
││+│⌿││ │ │
│└─┴─┘│ │ │
└─────┴─┴─┘

⌊/,⌈/             ⍝ fork for min_max
┌─────┬─┬─────┐
│┌─┬─┐│,│┌─┬─┐│
││⌊│/││ ││⌈│/││
│└─┴─┘│ │└─┴─┘│
└─────┴─┴─────┘```

This means that any of the four hybrid tokens / ⌿ \ ⍀ will not be interpreted as a function if there's a function to its left in the train. In order to fix one of these tokens as a replicate or expand function, it must be isolated from the function to its left:

```      (⍳/⍳)3        ⍝ → ⍳/ atop ⍳3 → RANK ERROR
RANK ERROR

(⍳{⍺/⍵}⍳)3    ⍝ → (⍳3){⍺/⍵}(⍳3) → (⍳3)/(⍳3)
1 2 2 3 3 3

(⍳(/∘⊢)⍳)3    ⍝ → (⍳3)/⊢(⍳3)
1 2 2 3 3 3

(2/⍳)3        ⍝ Agh-fork is OK
1 1 2 2 3 3```