Обычно результатом вызова Lisp’овой функции является один Lisp’овый объект. Однако, иногда для функции удобно вычислить несколько объектов и вернуть их. Common Lisp представляет механизм для прямой обработки нескольких значений. Механизм удобнее и эффективнее, чем исполнение трюков со списками или глобальными переменными.
Обычно не используется несколько значений. Для возврата и обработки нескольких значений требуются операторы. Если вызывающий функцию код не требует нескольких значений, однако вызываемая функция возвращает их несколько, то для кода берётся только первое значение. Все оставшиеся значения игнорируются. Если вызываемая функция возвращает ноль значений, вызывающий код в качестве значения получает nil.
values — это главный примитив для возврата нескольких значений. Он принимает любое количество аргументов и возвращает столько же значений. Если последняя форма тела функции является values с тремя аргументами, то вызов такой функции вернёт три значения. Другие операторы также возвращают несколько значений, но они могут быть описаны в терминах values. Некоторые встроенные Common Lisp функции, такая как floor, возвращают несколько значений.
Операторы, обрабатывающие несколько значений, представлены ниже:
Они задают форму для вычисления и указывают куда поместить значения возвращаемые данной формой.
Все аргументы в таком же порядке возвращаются, как значения. Например,
Выражение (values) возвращает ноль значений. Это стандартная идиома для возврата из функции нулевого количества значений.
Иногда необходимо указать явно, что функция будет возвращать только одно значение. Например, функция
будет возвращать два значения, потому что floor возвращает два значения. Может быть второе значение не имеет смысла в данном контексте, или есть причины не тратить время на вычисления второго значения. Функция values является стандартной идиомой для указания того, что будет возвращено только одно значение, как показано в следующем примере.
Это работает, потому что values возвращает только одно значения для каждой формы аргумента. Если форма аргумента возвращает несколько значений, то используется только первое, а остальные игнорируются.
В Common Lisp’е для вызывающего кода нет возможности различить, было ли возвращено просто одно значение или было возвращено только одно значение в с помощью values. Например значения, возвращённые выражением (+ 1 2) и (values (+ 1 2)), идентичны во всех отношениях: они оба просто равны 3.
Значение multiple-values-limit является положительным целым числом, которое невключительно указывает наибольшее возможное количество возвращаемых значений. Это значение зависит от реализации, но не может быть менее 20. (Разработчики рекомендуется делать это ограничение как можно большим без потери в производительности.) Смотрите lambda-parameters-limit и call-arguments-limit.
Все элементы списка list будут возвращены как несколько значений. Например:
Можно обозначить так,
но values-list может быть более ясным или эффективным.
multiple-value-list вычисляет форму form и возвращает список из того количества значений, которое было возвращено формой. Например,
Таким образом, multiple-value-list и values-list являются антиподами. FIXME
multiple-value-call сначала вычисляет function для получения функции и затем вычисляет все формы forms. Все значения форм forms собираются вместе (все, а не только первые) и передаются как аргументы функции. Результат multiple-value-call является тем, что вернула функция. Например:
multiple-value-prog1 вычисляет первую форму form и сохраняет все значения, возвращённые данной формой. Затем она слева направо вычисляет оставшиеся формы, игнорируя их значения. Значения, возвращённые первой формой, становятся результатом всей формы multiple-value-prog1. Смотрите prog1, которая всегда возвращает одно значение.
Вычисляется values-form и каждое значение результата связывается соответственно с переменными указанными в первом параметре. Если переменных больше, чем возвращаемых значений, для оставшихся переменных используется значение nil. Если значений больше, чем переменных, лишние значения игнорируются. Переменные связываются со значениями только на время выполнения форм тела, которое является неявным progn. Например:
Аргумент variables должен быть списком переменных. Вычисляется форма form и переменным присваиваются (не связываются) значения, возвращённые этой формой. Если переменных больше, чем значений, оставшимся переменным присваивается nil. Если значений больше, чем переменных, лишние значения игнорируются.
multiple-value-setq всегда возвращает одно значение, которое является первым из возвращённых значений формы form, или nil, если форма form вернула ноль значений.
Формы аргументов n и form вычисляются. Значение n должно быть неотрицательным целым, и форма form должна возвращать любое количество значение. Целое число n используется, как индекс (начиная с нуля), для доступа к списку значений. Форма возвращает элемент в позиции n из списка результатов вычисления формы form. Если позиции не существует, возвращается nil.
В качестве примера, mod мог бы быть определён так:
Часто случается так, что значение оператора или макроса определено как значение одного из подвыражений. Например, значение cond является значением последнего подвыражения в исполняемой ветке.
В большинстве таких случаев, если подвыражение возвращает несколько значений, тогда и оригинальная форма возвращает все эти значения. Эта передача значений, конечно, не будет иметь место, если не была выполнена специальная форма для обработки возврата нескольких значений.
Из операторов может быть неявно возвращено несколько значений в соответствие со следующими правилами: