13.2.3 Особенности списков аргументов

Наша простая тестовая функция, (lambda (a b c) (+ a b c)), определяет три переменные аргументов, поэтому ее необходимо вызывать с тремя аргументами: если вы попытаетесь вызвать ее только с двумя или четырьмя аргументами, вы получите ошибку wrong-number-of-arguments (см. Ошибки).

Часто удобно писать функцию, которая позволяет опускать определенные аргументы. Например, функция substring принимает три аргумента — строку, начальный индекс и конечный индекс, — но третий аргумент по умолчанию равен length строки, если вы его опускаете. Также удобно, когда определенные функции могут принимать неограниченное количество аргументов, как функции list и +.

Чтобы указать необязательные аргументы, которые могут быть пропущены при вызове функции, просто включите ключевое слово &optional перед необязательными аргументами. Чтобы указать список из нуля или более дополнительных аргументов, включите ключевое слово &rest перед одним последним аргументом.

Таким образом, полная синтаксическая структура списка аргументов выглядит так:

(required-vars…
 [&optional [optional-vars…]]
 [&rest rest-var])

Квадратные скобки указывают, что пункты &optional и &rest, а также переменные, следующие за ними, являются необязательными.

Вызов функции требует один фактический аргумент для каждой из required-vars. Может быть фактические аргументы для нуля или более optional-vars, и не может быть фактических аргументов после этого, если только список лямбда не использует &rest. В этом случае может быть любое количество дополнительных фактических аргументов.

Если фактические аргументы для необязательных и дополнительных переменных опущены, они всегда по умолчанию равны nil. Нет способа для функции отличить явный аргумент nil от пропущенного аргумента. Однако тело функции свободно рассматривать nil как сокращение для какого-либо другого значимого значения. Именно это делает substring; nil в качестве третьего аргумента для substring означает использование длины предоставленной строки.

Примечание Common Lisp: Common Lisp позволяет функции указывать, какое значение по умолчанию использовать, когда необязательный аргумент опущен; Emacs Lisp всегда использует nil. Emacs Lisp не поддерживает переменные supplied-p, которые сообщают, был ли аргумент передан явно.

Например, список аргументов, выглядящий так:

(a b &optional c d &rest e)

привязывает a и b к первым двум фактическим аргументам, которые являются обязательными. Если предоставлено еще один или два аргумента, c и d привязываются к ним соответственно; любые аргументы после первых четырех собираются в список, и e привязывается к этому списку. Таким образом, если есть только два аргумента, c, d и e равны nil; если два или три аргумента, d и e равны nil; если четыре аргумента или меньше, e равен nil. Обратите внимание, что ровно пять аргументов с явным аргументом nil, предоставленным для e, приведут к тому, что этот аргумент nil будет передан в виде списка с одним элементом, (nil), как и любое другое одиночное значение для e.

Невозможно иметь обязательные аргументы после необязательных — это не имело бы смысла. Чтобы понять, почему это должно быть так, предположим, что c в примере был необязательным, а d — обязательным. Предположим, дано три фактических аргумента; для какой переменной будет третий аргумент? Он будет использован для c или для d? Можно утверждать обе возможности. Точно так же не имеет смысла иметь какие-либо дополнительные аргументы (обязательные или необязательные) после аргумента &rest.

Вот несколько примеров списков аргументов и корректных вызовов:

(funcall (lambda (n) (1+ n))        ; Один обязательный:
         1)                         ; требует ровно один аргумент.
     ⇒ 2
(funcall (lambda (n &optional n1)   ; Один обязательный и один необязательный:
           (if n1 (+ n n1) (1+ n))) ; 1 или 2 аргумента.
         1 2)
     ⇒ 3
(funcall (lambda (n &rest ns)       ; Один обязательный и один rest:
           (+ n (apply '+ ns)))     ; 1 или более аргументов.
         1 2 3 4 5)
     ⇒ 15