2014-09-12 2 views
2

Вопрос: Можно ли написать общую функцию Lisp, которая принимает те же аргументы как по положению, так и по ключевому слову? Если да, то как?Общие функции Lisp, которые принимают аргументы либо по положению, либо по ключевому слову?

Например, как можно было переписать следующую функцию:

(defun fnx (&key a b c) 
    (list a b c)) 

Такой, что можно законно назвать его в каждом из следующих способов:

(fnx 1 2 3) 
(fnx :a 1 :b 2 :c 3) 
(fnx 1 2 :c 3) 
+4

Семантика не ясна. Что такое ': a: b'? Это один аргумент или два аргумента? Вы всегда можете использовать список аргументов '& rest' и самостоятельно разбирать его. Вообще-то я бы видел такие гибкие списки аргументов как плохой стиль, поскольку он делает ошибки более вероятными. Также обратите внимание, что в Common Lisp ключи необязательно должны быть ключевыми. Могут использоваться и обычные символы. –

+2

Невозможно. – Xach

ответ

3

Да, можно, но, нет , вы не хотите.

Точнее, если вы можете написать спецификацию, вы можете реализовать ее в Lisp, но я не думаю, что вы можете написать однозначную спецификацию. Например, что должны возвращать эти призывы:

(fnx :a :b :c) 
(fnx :a :c :b) 
(fnx :b :a :a) 
(fnx :a :a :a) 

и многие другие угловые случаи.

Вы можете, конечно, написать что-то вроде этого:

(defun parse-my-args (&rest args) 
    (let (a b c (curpos 0)) 
    ... some hairy processing 
    (values a b c))) 

(defun fnx (&rest args) 
    (multiple-values-bind (a b c) (parse-my-args args) 
    ...)) 

и объявить, что независимо от кода делает это правильно, но это не выглядит как хорошая идея.

Предлагаю вам подумать, что вы хотите достичь и задать вопрос об этом.

3

В дополнение к sds's answer, я бы порекомендовал вас прочитать this chapter из 'Practical Common Lisp'.

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

Здесь уместно цитата:

Остальные две комбинации, либо & опционально или & остальные параметры в сочетании с & ключевых параметров, может привести к несколько неожиданному поведению. < ...> Вы можете смело комбинировать & и & ключами параметров, но поведение может быть немного неожиданным изначально. Обычно наличие либо & остальные или & ключ в списке параметров вызывает все значения, оставшиеся после обязательной и & необязательных параметров были заполнены, чтобы быть обработаны определенным образом - либо собранно в список для параметра & параметр или присвоен соответствующему & ключ параметры, основанные на ключевых словах.Если оба & остальных и & ключ появится в списке параметров, то оба вещи происходят - все остальные значения, которые включают в себя ключевые слова сами, собраны в список, который привязан к & покоя параметра, и соответствующие значения также привязаны к параметрам &.

Так использование &rest (который, как вы можете параметры «индекс» функции) исключает возможность использования &key.

Конечно, любой безумный беспорядок с таким безумным инструментом, как Lisp, но в этом конкретном случае его не стоит.