Skip to content

Audit existing LAMBDAs for array-lifting support#180

Merged
jimmytacks merged 2 commits into
mainfrom
issue-179-array-lifting-audit
May 14, 2026
Merged

Audit existing LAMBDAs for array-lifting support#180
jimmytacks merged 2 commits into
mainfrom
issue-179-array-lifting-audit

Conversation

@jimmytacks
Copy link
Copy Markdown
Collaborator

@jimmytacks jimmytacks commented May 14, 2026

Summary

Per #179, audit every LAMBDA in the library for array-lifting support. Apply the dispatcher pattern wherever a scalar-input/scalar-output LAMBDA silently collapses or errors on array input.

Upgrades (⚠️ dispatcher added)

LAMBDA Lift on Reason
CELLTOPOS cell SUMPRODUCT(...SEQUENCE(LEN(letters))...) collapses arrays of addresses
POSTOCELL pos defensive; ADDRESS may lift naturally, dispatcher makes it explicit
MOVECELL cell calls CELLTOPOS internally
GRIDLOOKUP value forward (XMATCH) and reverse (CELLTOPOS) branches
INCEL address INDIRECT doesn't lift over arrays of addresses
NTH n @INDEX(flat, idx, 1) collapses to first when idx is array
CHARQ Text regex branch's COLUMNS(REGEXEXTRACT(...)) returns one array per Text, doesn't compose
REVERSESTRING text SEQUENCE(LEN(text), ...) errors when text is array
TLOOKUP Item defensive; MATCH may lift in modern Excel, dispatcher makes it explicit

Already lifts (✅ no change — confirmation tests added where relevant)

  • CONTAINS — XMATCH lifts on value
  • CIRCPOS — MOD lifts on moves and start (help already advertised this)
  • GetVar / GetVarAt / SplitState — already MAP over a column of states

Skip (➖ no scalar input, or output inherently an array)

GRIDAREA, ARROWMOVES, DEFAULTARROWS, DEFAULTMOVEDELTAS, KNIGHTDELTAS, BICOL, BIROW, MAXOF, MINOF, NTHOCCURRENCE, CUMSUMGRID, MAXOCCUR, MINOCCUR, EXPANDDIMENSIONS, SNAQUENCE, WRITEAT, INSERTAT, REVERSEARRAY, ROTATE, EXPLODE, CONSECGROUPS, COMBINATIONS, COMBININDICES, SetVar, SetVars, SetState, NewState, FINDFIRST, FINDALL, REDUCEUNTIL, REDUCEWHILE, SCANUNTIL, SCANWHILE.

Dispatcher shape

The scalar body is preserved inline as a LAMBDA inside LET (rather than a separate <NAME>_SCALAR workbook name) — this keeps the namespace tidy and the logic in one file:

scalar, LAMBDA(c, LET(... scalar body ..., scalar result)),
result, IF(OR(ROWS(arg) > 1, COLUMNS(arg) > 1),
            MAP(arg, scalar),
            scalar(arg)),
IF(Help?, Help, result)

The dispatcher sits after the ISOMITTED(...)ShowHelp branch, so =CELLTOPOS() etc. still return help text. Scalar callers are unaffected.

Test plan

  • All existing scalar tests still pass (no regressions).
  • 23 new tests added covering vertical, horizontal, and where useful 2D / range-of-cells inputs:
    • maps: CELLTOPOS (4), POSTOCELL (2), MOVECELL (2), GRIDLOOKUP (2), INCEL (2)
    • array: NTH (2), CONTAINS (1)
    • string: CHARQ (2), REVERSESTRING (2)
    • lookup: TLOOKUP (2)
    • math: CIRCPOS (2)
  • dotnet test addin/lambda-boss.AddinTests — 382 pass (was 359 pre-change).
  • dotnet test addin/lambda-boss.Tests — 828 pass.

Closes #179

🤖 Generated with Claude Code

jimmytacks and others added 2 commits May 14, 2026 19:54
Add a dispatcher to CELLTOPOS, POSTOCELL, MOVECELL, GRIDLOOKUP, INCEL so
they MAP over multi-cell input instead of silently collapsing it to a
scalar. The scalar body is preserved (defined as a LAMBDA inside LET,
not as a separate workbook name) so existing scalar callers are
unaffected.

GRIDAREA and the constant-table helpers (DEFAULTARROWS,
DEFAULTMOVEDELTAS, KNIGHTDELTAS, ARROWMOVES) are intentionally skipped
per the issue's classification (array output / no scalar input).

Adds array-input tests for each upgraded LAMBDA covering vertical,
horizontal, and where useful 2D and range-of-cells inputs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per Tim's review, expand the audit beyond the maps set to cover every
LAMBDA in the library.

Upgrades (dispatcher added — silently collapsed or errored on array input):
- NTH (array, lift on n): @INDEX(flat, idx, 1) collapses to first when
  idx is an array.
- CHARQ (string, lift on Text): regex branch uses
  COLUMNS(REGEXEXTRACT(Text, Char, 1)) which returns one array per Text
  and doesn't compose across an array of Texts.
- REVERSESTRING (string, lift on text): SEQUENCE(LEN(text), ...) requires
  a scalar length and errors when text is an array.
- TLOOKUP (lookup, lift on Item): defensive dispatcher — MATCH may lift
  on lookup_value in modern Excel but a dispatcher makes the behaviour
  explicit and consistent with the other upgrades.

Confirmation tests added (no code change — these already lift):
- CONTAINS — XMATCH lifts on value
- CIRCPOS — MOD lifts on moves and start (help already advertised this)

Skipped (no scalar input, or output inherently an array): BICOL, BIROW,
MAXOF, MINOF, NTHOCCURRENCE, CUMSUMGRID, MAXOCCUR, MINOCCUR,
EXPANDDIMENSIONS, SNAQUENCE, WRITEAT, INSERTAT, REVERSEARRAY, ROTATE,
EXPLODE, CONSECGROUPS, COMBINATIONS, COMBININDICES, SetVar, SetVars,
SetState, NewState, FINDFIRST, FINDALL, REDUCEUNTIL, REDUCEWHILE,
SCANUNTIL, SCANWHILE. GetVar/GetVarAt/SplitState already lift via
built-in MAP over a column of states (no test added — existing tests
already exercise the column path).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jimmytacks jimmytacks merged commit 8943543 into main May 14, 2026
1 check passed
@jimmytacks jimmytacks deleted the issue-179-array-lifting-audit branch May 14, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TASK: Audit existing LAMBDAs for array-lifting support

1 participant