Previous: , Up: Basic Concepts   [Contents][Index]


2.3 Multiple Values

It is not uncommon for one to iteratively update multiple state variables. To functionally do so, it is convenient to be able to produce multiple values from a single expression where the values are in turn consumed by the self-tail-recursive function. Unfortunately, Emacs Lisp does not support multiple values. To circumvent the limitation, a partial support for multiple-value forms is implemented10.

A cl-loop form involving multiple state variables:

(cl-loop with value1 = 0
         and value2 = '()
         and value3 = -1.0e+INF
         for number below 5
         do (cl-incf value1 number)
            (push number value2)
            (cl-callf max value3 number)
         finally return (list value1
                              (nreverse value2)
                              value3))
     ⇒ (10 (0 1 2 3 4) 4)

An equivalent for-do form:

(let ((value1 0)
      (value2 '())
      (value3 -1.0e+INF))
  (for-do ((number 5)
           (:do (cl-incf value1 number)
                (push number value2)
                (cl-callf max value3 number))))
  (list value1
        (nreverse value2)
        value3))
     ⇒ (10 (0 1 2 3 4) 4)

An equivalent for-fold form:

(for-fold ((value1 0)
           (value2 '())
           (value3 -1.0e+INF)
           (:result (list value1
                          (nreverse value2)
                          value3)))
    ((number 5)
     (:values (+ number value1)
              (cons number value2)
              (max number value3))))
     ⇒ (10 (0 1 2 3 4) 4)

Other than where the iteration forms expect a multiple-value form, multiple-value forms can appear in certain syntactic positions. It is an error for a multiple-value form to be in a syntactically invalid position. The formal grammar of multiple-value forms in an EBNF (Extended Backus–Naur Form) is as follows:

multiple-value-form = tail-form
                    | (cond (guard . body)…)
                    | (if guard multiple-value-form . body)
                    | (let varlist . body)
                    | (progn . body)

tail-form = expression | (:values [expression…])

body = ([expression…] multiple-value-form)

let = let | let*

progn = progn | save-current-buffer
      | save-excursion | save-restriction

Each multiple-value-form whose head is a global macro (see (elisp)Defining Macros) or a local macro (see (cl)Macro Bindings) is expanded (see (elisp)Expansion) ahead of time and further inspected. The form of varlist is as in normal let and let* forms. An expression and a guard are both expressions where the value of latter is specifically interpreted as a generalized Boolean11 value. A tail-form is a tail form where an expression is equivalent to the form (:values expression) and a (:values [expression…]) form produces as many values as there are expressions. It is an error for two tail forms of a multiple-value form to produce unmatched number of values. The grammar is actually a subset of Emacs Lisp’s special forms (see (elisp)Special Forms) with tail-form added. In a sense, special forms are extended to support multiple-value forms where possible.


Footnotes

(10)

In a standard Scheme implementation, a continuation can receive multiple values, and correspondingly a procedure can deliver multiple values to its continuation. This is unfeasible to implement in Emacs Lisp. Instead, a multiple-value form is transformed to imperative updates with macro-expansion-time checking of the number of values.

(11)

Following Common Lisp, a generalized Boolean value is an arbitrary Lisp object where only nil is false.


Previous: Sequence Forms, Up: Basic Concepts   [Contents][Index]