2013-05-30 7 views
5

SBCL 64bit, 1.1.7ошибка о дополнительных аргументах, для общего LISP

Если я хочу создать пакет и использовать немного символы из пакета: CL, я создам пакет, как этот:

(defpackage :foo 
    (:import-from :cl 
       :defun :defmacro :in-package 
       :null :car :cdr :cons :if 
       :eq)) 

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

(defun test (&optional a)) 

(test) 

invalid number of arguments: 0 
    [Condition of type SB-INT:SIMPLE-PROGRAM-ERROR] 

Restarts: 
0: [RETRY] Retry SLIME interactive evaluation request. 
1: [*ABORT] Return to SLIME's top level. 
2: [REMOVE-FD-HANDLER] Remove #<SB-IMPL::HANDLER INPUT on descriptor 10: #<CLOSURE (COMMON-LISP:LABELS SWANK-BACKEND::RUN :IN SWANK-BACKEND:ADD-FD-HANDLER) {100490B95B}>> 
3: [ABORT] Exit debugger, returning to top level. 

определить макрос получить ту же ошибку, б ут с дополнительной информацией:

(defmacro test (&rest body)) 

(test) 

error while parsing arguments to DEFMACRO TEST: 
    invalid number of elements in 
    () 
    to satisfy lambda list 
    (&REST BODY): 
    exactly 2 expected, but 0 found 
    [Condition of type SB-KERNEL::ARG-COUNT-ERROR] 

Я думаю, может быть, это из-за отсутствия некоторых символов из: CL, так как решить эту проблему? Благодарю.

ответ

7

Я считаю, что это будет пролить некоторый свет на эту проблему;)

CL-USER> (defpackage :foo 
    (:import-from :cl 
       :defun :defmacro :in-package 
       :null :car :cdr :cons :if 
       :eq)) 
#<PACKAGE "FOO"> 
CL-USER> (in-package :foo) 
#<COMMON-LISP:PACKAGE "FOO"> 
FOO> (defun bar (&optional baz)) 
; in: DEFUN BAR 
;  (SB-INT:NAMED-LAMBDA FOO::BAR 
;   (FOO::&OPTIONAL FOO::BAZ) 
;  (BLOCK FOO::BAR)) 
; 
; caught COMMON-LISP:STYLE-WARNING: 
; suspicious variable in lambda list: &OPTIONAL. 
; 
; caught COMMON-LISP:STYLE-WARNING: 
; suspicious variable in lambda list: &OPTIONAL. 
; 
; caught COMMON-LISP:STYLE-WARNING: 
; The variable &OPTIONAL is defined but never used. 
; 
; caught COMMON-LISP:STYLE-WARNING: 
; The variable BAZ is defined but never used. 
; 
; compilation unit finished 
; caught 4 STYLE-WARNING conditions 
BAR 
FOO> (in-package :cl) 
#<PACKAGE "COMMON-LISP"> 
CL> (defpackage :foo 
    (:import-from :cl 
       :defun :defmacro :in-package :&optional 
       :null :car :cdr :cons :if 
       :eq)) 
Select a symbol to be made accessible in package FOO: 
    1. COMMON-LISP:&OPTIONAL 
    2. FOO::&OPTIONAL 

Enter an integer (between 1 and 2): 1 

#<PACKAGE "FOO"> 
CL> (in-package :foo) 
#<COMMON-LISP:PACKAGE "FOO"> 
FOO> (defun bar (&optional baz)) 
; in: DEFUN BAR 
;  (SB-INT:NAMED-LAMBDA FOO::BAR 
;   (&OPTIONAL FOO::BAZ) 
;  (BLOCK FOO::BAR)) 
; 
; caught COMMON-LISP:STYLE-WARNING: 
; The variable BAZ is defined but never used. 
; 
; compilation unit finished 
; caught 1 STYLE-WARNING condition 
COMMON-LISP:STYLE-WARNING: redefining FOO::BAR in DEFUN 
BAR 
FOO> 

&optional, &rest и т.д. просто символы, как и любые другие, вы должны импортировать их тоже. Но, может быть, это не лучший способ импортировать из пакета cl ... если вы не уверены, что это то, что вам нужно. На всякий случай: вы можете :use весь пакет вместо :import-from символ по символу.

4

Если вы попробуете следующее в своем пакете FOO (cl:symbol-package '&optional), вы можете увидеть, какой пакет используется. Common Lisp ожидает, что используется в списках лямбда, но вы используете foo::&optional, и поскольку это символ без семантического значения, это просто параметр, как любой другой.

Одним из вариантов было бы добавить :&optional :&rest в список символов, которые вы импортируете из пакета CL, а другой - для цельной продажи, импортируя его, затеняя некоторые символы, которые вы хотите переопределить.

6

Интересно, что это может указывать на неясную разницу с SBCL и большинством других реализаций.

Если мы создадим новый пакет в SBCL, пакет по умолчанию не использует какой-либо другой пакет.

Так что это приводит к этому фанки разницы, скажем, GNU CLISP:

&optional является так называемый лямбда список ключевых слов.

Это GNU CLISP:

[1]> (defpackage :foo 
       (:import-from :cl 
       :defun :defmacro :in-package 
       :null :car :cdr :cons :if 
       :eq)) 
#<PACKAGE FOO> 
[2]> (in-package "FOO") 
#<PACKAGE FOO> 
FOO[3]> (defun test (&optional a)) 
TEST 
FOO[4]> (test) 
NIL 

Он работает в CLISP (и большинство других реализаций CL), так как он использует по умолчанию пакета "CL". SBCL не использованиеCL упаковка. Если вы не укажете пакет для использования, SBCL использует none. Большинство других реализаций создают новый пакет с набором полезных пакетов по умолчанию для наследования. Разработчики SBCL считали, что это особенно умно, но раскрывает несовместимости, которые, я думаю, не так уж и умны. Стандарт допускает интерпретацию SBCL DEFPACKAGE, но он был изменен на это, зная, что другие реализации этого не делают.

В GNU CLISP (и большинстве других реализаций CL) ваш оператор импорта не имеет эффекта, так как пакет все равно использует весь пакет «CL».

SBCL:

* (defpackage "BAR") 

#<PACKAGE "BAR"> 

* (package-use-list "BAR") 

NIL 

Сравните с CLISP:

[1]> (defpackage "BAR") 
#<PACKAGE BAR> 
[2]> (package-use-list "BAR") 
(#<PACKAGE COMMON-LISP>) 

Так что вам нужно импортировать список ключевых слов в лямбда SBCL в пакет.

Это также означает, что вам нужно написать объявление пакета, как это:

(defpackage :foo 
    (:import-from :cl 
    :defun :defmacro :in-package 
    :null :car :cdr :cons :if 
    :eq 
    :&optional) 
    (:use)) 

Над добавляет &optionalлямбда списка ключевых слов. Возможно, вы захотите добавить другие ключевые слова лямбда-списка.

В нем также указано, что нельзя использовать какой-либо пакет.

+0

Это намеренный выбор. Большинство реализаций будут автоматически импортировать CL, если пакеты не указаны, но не делают этого, если указан хотя бы один другой пакет. Если список импортированных пакетов пуст, если пакет не указан, вы, как правило, получаете меньше ошибок в строке. – Vatine

+0

@Vatine: добавление этой несовместимости кажется хуже. Я хочу иметь возможность набирать (defpackage «FOO») в REPL и получать полезный пакет. SBCL - не единственная реализация CL на планете. –

+1

Это не несовместимость, это определенная степень реализации, явно разрешенная стандартом. Если вы хотите создать переносную программу, вам уже пришлось явно предоставить список использования. – Xach