2016-05-25 2 views
3

УчитываяКак требовать ключевые слова в Common Lisp?

(defun show-arg (a) 
    (format t "a is ~a~%" a)) 

(defun show-key (&key a) 
    (format t "a is ~a~%" a)) 

оценивая

(show-arg) 

приведет к ошибке сказав "неверное число аргументов: 0", где

(show-key) 

покажет a is NIL

Как может Я получаю SHOW-KEY сигнал ошибки, как SHOW-ARG? Есть ли способ, кроме использования (unless a (error "a is required")) в теле функции? Я очень люблю аргументы ключевых слов и постоянно их использую, и почти всегда хочу, чтобы они были необходимы.

ответ

10

Аргументы ключевого слова всегда являются необязательными, поэтому вам необходимо вручную проверить, предоставлены ли они, и при необходимости сигнализировать об ошибке. Однако было бы лучше не требовать аргументы ключевых слов. Компилятор не будет распознавать их по мере необходимости и, таким образом, не даст вам сообщение об ошибке для отсутствия аргументов во время компиляции.

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

(defun foo (&key (keyarg nil keyargp)) 
    (unless keyargp (error "KEYARG is required.")) 
    (* keyarg 2)) 

Редактировать

Теперь, когда я думаю об этом немного больше, есть на самом деле способ получить ошибки компиляции времени для отсутствующих аргументов ключевых слов. Определите макрос компилятора для функции:

(defun foo (&key a b c d) 
    (* a b c d)) 

(define-compiler-macro foo (&whole whole &key (a nil ap) (b nil bp) 
            (c nil cp) (d nil dp)) 
    (declare (ignore a b c d)) 
    (unless (and ap bp cp dp) 
    (error "Missing arguments...")) 
    whole) 
+0

«Было бы лучше, если бы не потребовалось использование ключевых слов». Каким будет предложенный способ, например, инициализировать запись со многими обязательными полями? Например. как я могу увеличить удобочитаемость чего-то типа '(make-album« Led Zeppelin »« Physical Graffiti »1979 nil t 'rock)'? –

+0

@ leo-the-manic Обычно вы пытаетесь предоставить значения по умолчанию, которые имеют смысл, и пользователь будет только переопределять их, когда это необходимо. В этом примере первые два могут быть единственными необходимыми аргументами, а остальные могут быть оставлены как «NIL». В большинстве реальных программ это не проблема для удобочитаемости, потому что редко можно инициализировать записи с буквальными значениями. Обычно вы читаете значения из файла/базы данных/пользователя, а имена переменных позволят читателю понять, что они означают. Они также могут использовать свою среду разработки, такую ​​как SLIME, для просмотра списка аргументов. – jkiiski

6

Одним из возможных вариантов было бы:

(defun foo (&key (arg1 (error "missing arg1 in call to function foo"))) 
    arg1) 

С его помощью:

CL-USER 80 > (foo) 

Error: missing arg1 in call to function foo 
    1 (abort) Return to level 0. 
    2 Return to top loop level 0. 

Это даст ошибку во время выполнения, к сожалению, не во время компиляции ,

+3

Небольшой вариант этого заключается в том, чтобы обмануть сигнализацию ошибки в маленькую функцию, чтобы вы могли сказать '& key (foo (required))'. – Svante