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

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.

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

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.

(-,÷)5 ¯5 0.2

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.

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

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

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

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 ┌─┼───┐ + , ┌─┼───┐ - , ┌─┼─┐ × , ÷

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.

+⌿ ÷ ≢ ⍝ 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