Function Trains

Introduction

A Train is a derived function constructed from a sequence of 2 or 3 functions, or from 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:

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