2015-05-15 2 views
0

В результате размышлений вокруг проблемы с физическим упражнением я пытаюсь написать функцию, которая берет входное число и произвольный список длин делителей для проверки вместе с ожидаемой делимостью (т. Е. остаток 0) в качестве логического значения, возвращающего значение true, если все ожидания выполняются (по умолчанию используется значение true, если не указано).Common Lisp - Предоставление и отдых Списки как аргументы

Пример ввод:

(divisible-by 10 (5 t) (4 f) 2) => t 

Мое чтение привело к этой попытке в создании входа для функции:

(defun divisible-by (numerator &rest args (&key divisors (divisorp t))) 
    (loop...)) 

Моих простых тестовых случаев для такой ошибки ввода типа различных способов , и мой поиск через Google и прямо здесь, в Stack Overflow, не оказался плодотворным, и мне казалось, что мое понимание недостаточно для создания правильных ключевых слов.

Указатели на то, как реализовать такую ​​функцию, где мои попытки падают или почему такая функция не может быть реализована, как я изложил, было бы с благодарностью принято.

+1

Вы действительно хотите ключевые слова? Ваш пример ввода, похоже, не использует их. – npostavs

+0

@npostavs не очень, изначально я попытался использовать & optional вместо этого, но в моем чтении было предложено использовать ключ & в сочетании с & rest вместо этого, и я не мог найти никаких примеров & rest и & необязательно использоваться в комбинации, поскольку я хочу здесь , – Sam

+1

На самом деле, я не понимаю, зачем вам что-то сверх '& rest'. – npostavs

ответ

1

Вам ничего не нужно за &rest:

(defun divisible-p (number &rest divisors) 
    "Check whether number is divisible by divisors." 
    (dolist (spec divisors t) ; For each 'divisor' in divisors 
    (etypecase spec 
     ;; If divisor is a list, test if modulus of first value is 0 
     ;; then compare to second (boolean) 
     (cons (unless (eq (zerop (mod number (first spec))) 
         (second spec)) 
       (return nil))) 
     ;; If divisor is an integer, return t if modulus == 0 
     (integer (unless (zerop (mod number spec)) 
       (return nil)))))) 

(divisible-p 10 '(5 t) '(4 nil) 2) 
==> T 
(divisible-p 10 '(5 t) '(4 nil) 2 3) 
==> NIL 

Обратите внимание, что вам нужно привести список аргументов, в противном случае вы получите сообщение об ошибке, что не существует никакой функции 5.

Я не уверен, что вы пытаетесь достичь с помощью &key, но они не могут быть повторены в ХЛ, то есть, если вы пишете

(defun foo (&key a) (print a)) 
(foo :a 1 :a 2 :a 3) 

будет распечатана только 3, 1 & 2 будет проигнорировано ,

+0

Спасибо за решение. Это безумное поручение, чтобы попытаться вырвать компоненты, входящие в состав и отдохнуть с самого начала, как я пытался, или это можно сделать? – Sam

+0

Я не уверен, что вы имеете в виду, но, пожалуйста, см. Edit – sds

+0

. Редактирование разъясняет использование & key для меня, спасибо! То, что я пытаюсь спросить, я полагаю, заключается в следующем: Can & rest может сопровождаться чем-то другим, кроме одного аргумента, чтобы содержать результирующий список, и если да, то какой пример простого примера использования? – Sam

1

Я не вижу продуктивного способа смешивания &rest и &key для решения этой проблемы. Вот пример использования только &key:

(defun divisible-by (numerator &key divisors not-divisors) 
    (flet ((dividesp (denom) (= 0 (mod numerator denom)))) 
    (and (every #'dividesp divisors) 
      (notany #'dividesp not-divisors)))) 

;; Call like: 
(divisible-by 10 :divisors (list 2 5) :not-divisors (list 4 6)) 
=> t 

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

(defun divisible-by (numerator &rest args &key divisors (divisorp t)) 
    (print args) 
    (print divisors) 
    (print divisorp)) 

;; Calling would look like this 
(divisible-by 10 :divisors (list 11 2) :divisorp nil) 

-> (:DIVISORS (11 2) :DIVISORP NIL) 
-> (11 2) 
-> NIL 

Ваш желаемый вход не точно для функции. Вызовы функций не изменяют синтаксис их аргументов: (5 t) будет функцией 5, вызываемой с аргументом t, но 5 не является функцией, поэтому вы получаете ошибку, независимо от лямбда-списка.

0

Defun принимает обычный Лямбда-лист. В этом нет деструктурирования.

&Rest принимает только один символ, который привязан к остальным аргументов после заполнения всех необходимых и необязательных параметров. Если вы хотите разрушить его, используйте destructuring-bind внутри тела функции.

Иногда может оказаться целесообразным использовать макрос, который принимает лямбда-лист , чтобы запрограммировать форму вызова функции.

Смежные вопросы