Higher-order functions move relationships between parameters into reusable helpers. A curried function receives one argument at a time. A composition helper connects one function's output to the next function's input. Their types should explain those relationships rather than accepting unrelated values and hoping the calls succeed.
You will implement currying, left-to-right composition, mapping over successful results, and memoization. Each helper has a small runtime wrapper so hidden tests can verify behavior independently from its compiler contract. Watch the boundary between presence and truthiness: a cached zero is a valid computed result, not a cache miss. A failed result should pass through without calling its success mapper. These examples use pure functions so caching doesn't conceal time-dependent work or side effects.
function curry3<A,B,C,R>(fn:(a:A,b:B,c:C)=>R):(a:A)=>(b:B)=>(c:C)=>R {return a=>b=>c=>fn(a,b,c);}
function solve(values:number[]):number {return curry3((base:number,rate:number,offset:number)=>base*rate+offset)(values[0])(values[1])(values[2]);}
A complete implementation for the first scenario; trace its input before editing.