Общая функция вызова 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
только один аргумент изменился.
перечислите каждый аргумент ключевого слова с их значениями по умолчанию, а затем передайте их с необходимыми изменениями в
REMOVE
,перечислять только список остальных аргументов, манипулировать этим списком аргументов и передавать новый через
APPLY
вREMOVE
,смесь 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)
И здесь количество аргументов в позиции ключевого слова четное.