# Functions and bindings

Lexical scope, closures and lambda lists behave as in Common Lisp. The one
namespace means a bound function, model or optimizer is called as `(f x)`.

## Bindings

- `let` evaluates every initializer in the enclosing environment, then binds.
- `let*` opens a new lexical scope per binding, so an earlier closure never
  captures a later binding.
- `setq` rebinds existing variables, pairwise: `(setq a 1 b 2)`. Rebinding a
  tensor variable builds a new graph value; it never mutates a tensor during
  training.
- `incf`, `decf` and `push` are [prelude](https://sexpgpu.041.io/docs/prelude.md) macros over `setq`;
  they take variable names, not generalized places.
- `defvar` binds a module-level name once; a second definition of the same
  name in the module is `E-EVAL-036`.

## Lambda lists

`defun`, `lambda`, `defmodel`, `defoptimizer`, `flet` and `labels` accept:

```lisp
(defun f (a b                       ; required
          &optional (c 1 c-given)   ; default and supplied-p
          &rest more                ; the remaining arguments as a list
          &key ((:learning-rate lr) 0.01 lr-given) (eps 1e-8)
          &allow-other-keys
          &aux (d (* a b)))         ; local bindings, no argument
  ...)
```

- Defaults see the bindings before them.
- A keyword can be renamed: `((:learning-rate lr) 0.01)`.
- The first occurrence of a repeated keyword argument wins.
- Unknown keys fail (`E-EVAL-010`, and the fix lists the accepted keywords)
  unless the lambda list has `&allow-other-keys` or the call passes a true
  `:allow-other-keys`.
- The wrong number of arguments is `E-EVAL-011`.
- Duplicate bindings and malformed lambda lists are `E-EVAL-005`.

Macro lambda lists add nested list patterns, `&body` as an alias for
`&rest`, `&whole` for the whole call or nested list, and `&environment`
for the caller's lexical environment. `destructuring-bind` uses the same
pattern grammar on an evaluated list:

```lisp
(destructuring-bind (a (b c) &key (d 0)) (list 1 (list 2 3) :d 4)
  (+ a b c d)) ; 10
```

## apply

`(apply f arg... final-list)` calls `f` with the explicit arguments followed
by the elements of the final list. Models, model constructors and
configured-optimizer constructors are callable too. Macros are expanded,
not called, so they cannot be passed to `apply`.

## Local functions

- `flet` defines local functions whose bodies see the enclosing environment.
- `labels` makes them mutually recursive.
- `macrolet` defines local macros; see [macros](https://sexpgpu.041.io/docs/macros.md).

```lisp
(labels ((even? (n) (if (= n 0) true (odd? (- n 1))))
         (odd? (n) (if (= n 0) false (even? (- n 1)))))
  (even? 10)) ; true
```

User functions have a 256-frame recursion limit (`E-EVAL-040`) and no tail
calls. Use [`repeat`, `map`, `reduce`](https://sexpgpu.041.io/docs/builtins.md#lists-and-higher-order)
or [`dotimes`](https://sexpgpu.041.io/docs/control.md#iteration) to generate many things.

## Closures as structure

A model is a closure over its parameters, a schedule a closure over its
constants, and an optimizer argument may be any function:

```lisp
(defun stable-then-decay (peak &key (decay-fraction 0.7))
  (lambda (ctx)
    (* peak (minimum 1.0 (/ (- 1.0 (getf ctx :progress)) decay-fraction)))))
```

Related: [macros](https://sexpgpu.041.io/docs/macros.md), [models](https://sexpgpu.041.io/docs/models.md), [special forms](https://sexpgpu.041.io/docs/special-forms.md).

---

SexpGPU documentation. Every page: https://sexpgpu.041.io/llms.txt
