Common Lisp: Работа с параметрами &rest

Может ли кто-нибудь сказать мне, как работать с параметрами, хранящимися в значении, указанном &rest.

Я много читал, и кажется, что авторы умеют только перечислять все параметры.

(defun test (a &rest b) b)

Это приятно видеть, но не очень полезно.

Лучшее, что я нашел до сих пор, это использовать first, second и т. д., чтобы получить параметр, который вы ищете.

(defun test (a &rest b)
    (first b))

Я заметил, что этот метод перестает работать с десятым параметром, но спецификация (из того, что я читал) поддерживает минимум 50. Даже если шансы, что я буду использовать 50 параметров, невелики, я хотел бы знать, как получить к ним доступ.

Спасибо


person BlueBadger    schedule 10.03.2009    source источник


Ответы (5)


Функции доступа FIRST, SECOND и т. д. являются «просто» служебными функциями поверх CAR/CDR или NTH. Итак, я думаю, ответ на ваш конкретный вопрос: «используйте NTH или ELT» (или создайте свои собственные специальные функции доступа).

Если вы хотите, вы можете определить ОДИННАДЦАТЬ как:

(defun eleventh (list) (nth 10 list))

Однако я обнаружил, что в основном использую аргументы &REST, когда есть 0 или более вещей, с которыми я хочу что-то сделать, на самом деле не заботясь о конкретной позиции данного аргумента в списке &REST. Обычно это влечет за собой использование LOOP, DO или DOLIST для обхода аргументов и выполнения каких-либо действий с каждым из них; семейство MAP или (иногда) REDUCE.

person Vatine    schedule 10.03.2009

Параметр Rest - это просто список. Вы можете справиться с этим, используя обычные операции со списками.

(defun test (a &rest b))
  (dolist (s b)
    (when (> s 1)
      (print s)
      (do-something-else b)))
person Marko    schedule 10.03.2009
comment
Это список внутри функции, но передача списка как &rest может не дать желаемого поведения (в отличие от params[] из, скажем, языка C#). Новичку (например, мне) довольно легко совершить эту ошибку: предположим, что ваша функция рекурсивна с параметром &rest. Затем во время рекурсии вы не можете передать список в качестве параметра &rest, вы должны использовать apply #'yourfun... - person PawelP; 14.11.2014
comment
@PawelP Если вам нужно передать список, просто используйте обычный параметр функции для передачи этого списка. &rest params - это просто простой способ вызвать функцию с переменным числом параметров, не заключая их в список самостоятельно на каждом сайте вызова. - person Marko; 19.11.2014
comment
Что меня ввело в заблуждение, так это тот факт, что внутри функции доступ к параметру &rest осуществляется так же, как к списку, однако вы не можете передать его напрямую как параметр &rest рекурсивно (потому что вы будете передавать список, и это, вероятно, не то, что вы хотите). Я думаю, что я не единственный новичок, который попался в эту ловушку. Таким образом, похоже, что LISP делает некоторую упаковку за кулисами при вызове функции (составляет список из параметров, которые анализируются как &rest). Конечно, ваше объяснение правильное, я не оспариваю это. - person PawelP; 19.11.2014

На самом деле функция полезная. Вам нужно только попробовать.

CL-USER 1 > (defun test (a &rest b) b)
TEST

CL-USER 2 > (test 1 2 3 4)
(2 3 4)

Итак, вы видите, что B — это просто список аргументов. Таким образом, применимы все операции списка и последовательности. Нет ничего волшебного. Есть функции для доступа к элементу NTH, функции для удаления элементов и т. д.

В Common Lisp HyperSpec перечислены соответствующие функции:

14. Словарь Conses

17. Словарь последовательностей

Для базового руководства по Лиспу ознакомьтесь с книгой Турецки:

Common Lisp: краткое введение в символьные вычисления

Книга доступна для скачивания в формате PDF и Postscript. Он учит основам Common Lisp.

person Rainer Joswig    schedule 10.03.2009
comment
Спасибо за ссылку на нежное введение. Я просмотрел первые пару глав и должен сказать, что очень хотел бы, чтобы это была первая книга по программированию, которую я прочитал. Это очень хорошо сделано. - person BlueBadger; 10.03.2009

Вы также можете использовать destructuring-bind:

(defun my-function (&rest arguments)
  (destructuring-bind (a b &rest c) arguments
    (format nil "~A,~A followed with ~A" a b c)))

CL-USER> (my-function 1 2 "Give" 'me "more" 'arguments!!)
==> "1,2 followed with (Give ME more ARGUMENTS!!)"
person Mark Cox    schedule 10.03.2009

У меня просто есть рекурсивная итерация, чтобы пройти их все, я думаю, что dolist лучше, но мне нравится использовать старомодный способ

person Isaiah    schedule 28.09.2010