# `LAMBDA` The `LAMBDA` operator builds a callable function out of a Calc formula. ## Using `LAMBDA` * `LAMBDA` expects a list of parameter names, followed by an expression. * All parameter names must be valid identifiers, and must not match any names already defined by Calc, nor any possible cell references. Identifiers are not case-sensitive. Identifiers must start with a letter, and may contain only letters, numbers, and underscores (`_`). * You may specify no parameters, if you want the function to operate the same way every time it is called (this may be useful if its expression includes volatile operators such as `RAND` or `TIME`). * The result of a `LAMBDA` is a function. Don't expect that to show up in the spreadsheet in any useful way! You must call the function to use it. * Call a `LAMBDA` function just like you call a built-in function: put the name of the function (either a named range, a cell reference, or the `LAMBDA` expression itself) into your formula before a pair of parentheses containing the arguments you want to pass to the function. * If you are nesting one `LAMBDA` inside another, you may use the same parameter name in both (if you really want - this can easily make things hard to read!). The innermost `LAMBDA` specifying a parameter of a given name applies at each level of scope. This also works with `LET`. * A function can call itself (this is called recursion), but you must be able to refer to it from within the function. For example, if cell `A1` is a `LAMBDA` formula, the body of the `LAMBDA` can call itself by referring to `A1`. You can name your `LAMBDA` cell to make this easier to read. * If you want your `LAMBDA` function to permit optional parameters, enclose those parameter names (in the parameter list, not in the body) in brackets, like this: > =LAMBDA(name1, name2, [name3], [name4], expression) * `ISOMITTED` can be used within a `LAMBDA` body to detect whether an optional parameter was provided or omitted. * Optional parameters must not appear before any required parameters in the parameter list. Your parameters can appear in any order inside the body. ### Examples (This form is permitted, but not recommended, as it is difficult to read.) > `A1`: `=LAMBDA(a,b,a+b)(3*5,7/(6+4))` `A1` will show `15.7` (=`(3*5)+(7/(6+4))` ) --- > `A1`: `=LAMBDA(a,b,a+b)` > > `B1`: `=A1(3*5, 7/(6+4))` `B1` will show `15.7` --- If `MY_SUM` is `A1`: > `A1`: `=LAMBDA(a,b,a+b)` > > `B1`: `=MY_SUM(3*5,7/(6+4))` `B1` will show `15.7` --- If `FACT` is `A1`: > `A1`: `=LAMBDA(n,IF(n>1,n*FACT(n-1),1))` > > `B1`: `=FACT(5)` `B1` will show `120` (`FACT` duplicates the functionality of the built-in `FACTORIAL` function, but is less efficient) ## How it Works * The `ocLambda` `OpCode` corresponds to the `LAMBDA` operator * `ocLambda` is set up as a jump `OpCode`, meaning that it has special rules for what parameters are evaluated, and when. * The first stage of the compiler tokenizes the elements of the `LAMBDA` expression, like any other. It also looks for the lambda parameters, and interns them as identifiers. * The second stage of the compiler sets up the jump table with the parameters and body. It also looks for any parameters between `ocTableRefOpen`/`ocTableRefClose` (which correspond to brackets), and sets `mIsOptional` for those parameters. * The `ocLambda` is built in the compiled code as a sequence consisting of the `ocLambda` token itself, then the parameter names (`svStringName`) separated by `ocSep`, followed by another `ocSep`, then the lambda body, with `ocClose` at the end. The jump table points to the `ocLambda`, each `ocSep`, and the `ocClose`, which allows the interpreter to find each parameter name (the `ocLambda` and `ocSep`s except the last), the body (the last `ocSep`), and the position where execution continues (`ocClose`). * When interpreted, `ocLambda` causes a `ScFormulaFunction` to be built using the contents of the jump table. At this point all parameters are counted, and that information is passed on to the next step. * `ScFormulaFunction`'s constructor clones the lambda body and saves the interpreter's contextual information, then locates each use of each parameter in the scope of that identifier in the body and makes note of where it is. * When a `ScFormulaFunction` is called via `ScInterpreter::ScCall`, it builds a new interpreter out of the saved context, performs the replacements specified, and executes the interpreter to obtain a result. This means that the `LAMBDA` body is executed in the same context that the `LAMBDA` appeared in. * `ocLambda` is itself nonvolatile, and overrides any volatility in its body, since the `LAMBDA` never produces a different callable, no matter what functions appear in the body. * The presence of an enclosing `LAMBDA` also prevents circular references from being a problem, as the body of a `LAMBDA` is not executed until the cell containing it already has a value. This allows recursion. * `LAMBDA` does not currently check for infinite recursion; avoid recursive calls that can cause such a loop.