Общая функция вызова lisp без применения приводит к нечетному числу ключевых слов

В настоящее время я изучаю общий язык и наткнулся на вопрос, который я не мог ответить сам:

(defun find-all (item seq &rest keyword-args &key (test #'eql)
                     test-not &allow-other-keys)
 (if test-not
   (apply #'remove item seq
          :test-not (complement test-not) keyword-args)
   (apply #'remove item seq
          :test (complement test) keyword-args)))

Функция используется для поиска каждого элемента в последовательном элементе поиска в соответствии с тестовой функцией. К сожалению, я не понимаю, почему функция "применить" была использована здесь. Разве не должно быть возможно просто вызвать удаление без применения? В предупреждении говорится: "У функции есть нечетное количество аргументов в части ключевого слова", если я вызываю удалить без применения.

Я надеюсь, что вы можете помочь мне, заранее спасибо!

2 ответа

Решение

УДАЛИТЬ И НАЙТИ ВСЕ

REMOVE принимает несколько ключевых аргументов: from-end, test, test-not, start, end, count и key.

Теперь в функции FIND-ALL Вы хотите изменить только одно: либо test, либо test-not, а затем вызвать REMOVE,

Как написать список параметров FIND-ALL

Теперь у вас есть три основных варианта написания списка параметров: FIND-ALL, так как это в основном так же, как REMOVE только один аргумент изменился.

  1. перечислите каждый аргумент ключевого слова с их значениями по умолчанию, а затем передайте их с необходимыми изменениями в REMOVE,

  2. перечислять только список остальных аргументов, манипулировать этим списком аргументов и передавать новый через APPLY в REMOVE,

  3. смесь 1. и 2. как в примере выше. Перечислите только обязательные аргументы и аргументы ключевого слова для изменения, а также список остальных аргументов ключевого слова, предоставленных во время вызова. Вызов REMOVE с помощью APPLY,

Насколько хороши три возможности?

Теперь 1. имеет то преимущество, что вы видите полный список параметров для FIND-ALL и что ему не нужно составлять список аргументов. Лисп может проверить кое-что из этого. Но вам действительно нужно скопировать все аргументы в вашем списке параметров и позже в вызовах REMOVE, Возможно, но не так здорово.

Тогда 2. имеет недостаток, заключающийся в отсутствии видимого списка параметров для FIND-ALL, но было бы проще написать несколько функций для управления списками аргументов. 3. относительно легко написать, но также не имеет полного списка параметров.

Ваш пример

Таким образом, в вашем примере это версия 3 выше:

  • необходимые аргументы передаются в первую очередь
  • Далее идут измененные аргументы
  • последний список всех ключевых аргументов

Если вы хотите передать существующий список аргументов как часть аргументов функции, тогда вам нужно APPLY, Вот почему он используется там. APPLY вызывает функцию с аргументами, взятыми из списка.

CL-USER 1 > (apply #'+ 1 2 '(3 4 5))
15

CL-USER 2 > (let ((numbers '(3 4 5)))
              (apply #'+ 1 2 numbers))
15


CL-USER 3 > (+ 1 2 3 4 5)
15

Давайте возьмем для примера подпись REMOVE:

remove item sequence &key from-end test test-not start end count key 
=> result-sequence

Вышеуказанное означает, что функция принимает 2 обязательных аргумента, item а также sequence и дополнительные ключевые слова аргументы, которые должны быть даны с :key value синтаксис. Если вы даете только ключ или значение, например:

(remove x list :count)

Тогда это недействительно. Простой тест состоит в том, чтобы посмотреть на количество параметров в позиции ключевого слова и проверить, является ли количество заданных аргументов четным. Когда это странно, вы знаете, что-то не так.

Если вы позвоните:

(remove item seq args)

Вы в том же случае. Не важно что args это список в вашем конкретном случае.

Применять

APPLY это более общий способ вызова функции: последний аргумент - это список дополнительных аргументов.

предполагать args связан с (3 4), затем:

(apply #'+ 1 args)

эквивалентно:

(+ 1 3 4)

Это работает и с аргументами ключевых слов; если args это список (:count 1), затем:

(apply #'remove item seq args)

эквивалентно:

(remove item seq :count 1)

И здесь количество аргументов в позиции ключевого слова четное.

Другие вопросы по тегам