With the argument-gathering helper in place, more aggregate functions are almost free. Today you add MIN and MAX - two facets of the same reduce-over-a-range idea, differing only in the comparison.
Add MIN and MAX as reductions over the numeric values of their arguments.
MIN and MAX are the same shape as SUM: gather the numeric values with the
helper, then reduce them - but instead of adding, you keep the running smallest
or largest. They are genuinely two facets of one idea, so they share a case,
differing only in the comparison (< versus >). Over 1, 2, 3 that gives 1 and
3; raise a cell and MAX tracks it to 10.
The one edge worth deciding is what an empty set of numbers reduces to - a range
of all-blank cells. Real spreadsheets return 0 for MIN/MAX of nothing, so we
seed the result at 0 when no numbers are found rather than erroring. Keeping the
same argument helper across every aggregate is what makes these functions small: the
work of expanding ranges and filtering to numbers was done once in the last lesson,
and each new function is just a different fold over the result.
case "MIN", "MAX":xs := s.numArgs(n.Args)if len(xs) == 0 { return Value{Kind: Number, Num: 0} }m := xs[0]for _, x := range xs {if n.Name == "MIN" && x < m { m = x }if n.Name == "MAX" && x > m { m = x }}return Value{Kind: Number, Num: m}