Higher-Order Function

Context: FIT1008_MOC, FIT2102_MOC · relies on functions being first-class · pairs with Generator Expression and List Comprehension · the f in a Tree Traversal · JavaScript forms and the Array methods in JavaScript Functions as Values

Quick Revision

  • 🎯 Objective: a function that takes and/or returns a function ➔ makes behaviour a parameter.
  • 📦 Core Components: closures, currying/partial, map/filter/reduce, decorators.
  • ⚡ Key Constraint: an ordinary -overhead call; total cost = number of applications (e.g. over a collection).

📝 Core

1. The HOF (First-Class Functions)

  • Definition ➔ takes a function as argument and/or returns a function.
  • Enabled by ➔ functions being first-class objects (assignable, storable, passable, returnable).
  • Payoff ➔ behaviour becomes a parameter ➔ foundation of map/filter/reduce and the callback f in a Tree Traversal.
  • Why JavaScript qualifies ➔ functions are objects there, so const hi = function(p) {…} and passing hi onward have been legal since the language’s inception — no language feature had to be added (Programming Paradigms).

2. The HOF Toolkit

  • Closure ➔ inner function capturing enclosing-scope variables (outlives the outer call).
  • Currying/partialf(a,b)f(a)(b) (functools.partial; in JS just x => y => …).
  • map/filter/reduce ➔ transform / select / aggregate ➔ compose into pipelines.
  • Decorator ➔ a HOF wrapping a function (@dec is f = dec(f)) ➔ memoisation rescues naive Fibonacci.

⚙️ Core Implementation

🔹 Taking, returning, and the three list HOFs

🔹 JavaScript: the same three, as Array methods (FIT2102)

⚖️ Core Decision Matrix

ToolFormReplaces / adds
mapmap(f, xs) · xs.map(f)a transform loop
filterfilter(p, xs) · xs.filter(p)a select loop
reduce/foldreduce(g, xs, init) · xs.reduce(g, init)an accumulate loop
forEachxs.forEach(f) (JS)a loop run purely for effect
closureinner fn capturing scopeconfigured functions
partial/currypartial(f, a) · x => y => …specialise a general fn
decorator@dec = f = dec(f)wrap (logging, memoise, timing)

When It Flips: abstraction/reuse (one traverse(tree, f) covers infinitely many behaviours) + composability ( pipelines); the trade-off is that nested closures / point-free style can obscure control flow.

📊 Exam Execution Trace

Manual Execution Trace

A lazy select→transform→aggregate pipeline:

Step / StateStageCallStreams
0 (Init)
1filterfilter(p, xs)keep odds
2mapmap(f, ...)square each
3reducereduce(add, ...)sum

With generators the whole pipeline is memory (no intermediate lists). JS Array methods are eager by contrast — each stage materialises a new array.

Applied Exercise

Problem: Show a decorator is a HOF. Derivation Proof / Hand-Calculation Walkthrough:

Final Extracted Output: @lru_cache memoisation turns naive Fibonacci from to — a HOF wrapper.

🧠 Active Recall