Skip to content

Direct Functions in Depth

The beginner tutorial introduced dfns. This tutorial covers the details: scoping rules, guard patterns, recursion techniques, and common idioms.

Scoping rules

Dfns use lexical scope. A variable assigned inside a dfn is local. An unassigned name looks outward through enclosing dfns to the workspace:

      x ← 100
      f ← {y ← 10 ⋄ x + y + ⍵}
      f 1
111

y is local to f. x is found in the workspace.

Nested dfns see their enclosing scope:

      outer ← {
          scale ← ⍵
          {scale × ⍵}
      }
      double ← outer 2
      double 5
10

The inner dfn captures scale from outer. This is a closure.

Guard patterns

Multiple conditions

Guards are checked top to bottom. The first true guard returns:

      classify ← {
          ⍵ < 0   : 'negative'
          ⍵ = 0   : 'zero'
          'positive'
      }

The last expression (no guard) is the default — reached only if all guards are false.

Guards with scalar arguments only

Guards expect a scalar boolean (0 or 1). If the condition produces an array, this is an error.

Recursion patterns

Simple recursion

      fact ← {⍵ ≤ 1 : 1 ⋄ ⍵ × ∇ ⍵ - 1}

Accumulator pattern

      fact ← {⍺ ← 1 ⋄ ⍵ ≤ 1 : ⍺ ⋄ (⍺×⍵) ∇ ⍵-1}

The default ⍺←1 lets it be called monadically. The left argument accumulates the result.

Recursion on arrays

      ⍝ Quicksort
      qsort ← {1≥⍴⍵ : ⍵ ⋄ (∇ ⍵/⍨⍵<p) , (⍵/⍨⍵=p) , ∇ ⍵/⍨⍵>p←⍵[1]}

Common idioms

Identity / default

      {⍵}               ⍝ identity (right tack equivalent)
      {⍺ ← 0 ⋄ ⍺ + ⍵}  ⍝ add with default left arg of 0

Pipeline style

      process ← {
          data ← clean ⍵
          data ← transform data
          summarise data
      }

Each step assigns to data, threading the computation through.

Anonymous dfns

Dfns don't have to be named:

      {⍵ × ⍵} 5         ⍝ square, inline
25
      {⍺ + ⍵}/ ⍳10      ⍝ anonymous dfn as operand to reduce
55

Key points

  • Dfns use lexical scope — inner dfns can capture variables from outer dfns (closures)
  • Guards are checked top to bottom; the last unguarded expression is the default
  • ∇ enables recursion; use an accumulator pattern for tail-style recursion
  • Dfns are values: assign them, pass them to operators, use them inline

Next: Direct Operators