S-exp GPU
All pages
Docs · The languageMarkdown

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 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:

(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:

(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.
(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 or dotimes 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:

(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, models, special forms.