обработка пакетов ": cl" между реализациями Common Lisp - PullRequest
0 голосов
/ 23 апреля 2020

Почему происходит такое поведение? Кроме того, это несоответствие, определяемое реализацией, или один из этих REPL неправильный?

Пожалуйста, рассмотрите этот код Common Lisp. ..

(defpackage :new)
(in-package new)
(+ 2 2)

В CMUCL это число равно 4.

В SBCL это возвращает ошибку:

; in: + 2
;     (NEW::+ 2 2)
;
; caught COMMON-LISP:STYLE-WARNING:
;   undefined function: NEW::+
;
; compilation unit finished
;   Undefined function:
;     +
;   caught 1 STYLE-WARNING condition

debugger invoked on a COMMON-LISP:UNDEFINED-FUNCTION in thread
#<THREAD "main thread" RUNNING {1000508083}>:
  The function NEW::+ is undefined.

Однако, SBCL будет правильно вызывать «+», когда он оценивается как

(cl:+ 2 2)

, и CMUCL также работает с этим.

Когда я посмотрел в HyperSpe c Я не смог найти четкий раздел, который касается этого контекста. Самое близкое, что я смог найти, это: Раздел 11.1.2.2 Пакет COMMON-LISP-USER . Что заставляет меня верить, что SBCL имеет правильную интерпретацию; что «NEW» не наследует символы от «COMMON-LISP», поэтому весь язык Common Lisp недоступен из «NEW». Но действительно странно, что три строки убили бы весь язык, поэтому мне все еще неясно.

Ответы [ 3 ]

3 голосов
/ 23 апреля 2020

В стандарте CL не определено, какие пакеты для используют , когда в DEFPACKAGE отсутствует предложение :use.

CLHS: DEFPACKAGE :

Аргументы: use устанавливают пакеты, от которых будет наследоваться пакет с именем package-name. Если: use не предоставлено, по умолчанию используется то же зависящее от реализации значение , что и аргумент: use для make-package.

SBCL решил не use любой пакет.

Традиционно для другой реализации CL обычно используется пакет CL плюс некоторые пакеты расширения. Тогда предполагалось, что новый пакет по умолчанию полезен для программирования на Лиспе, такой как пакет CL-USER.

Для переносимого кода вам нужно указать, какие пакеты должен использовать пакет . Обычно defpackage и make-package являются операторами для просмотра.

1 голос
/ 23 апреля 2020

Вы можете указать пакеты для наследования символов в defpackage с помощью :use, или вы можете вызвать use-package в том же конце; Я обычно делаю это в defpackage. Я не знал, что CMUCL вел себя не так, как SBCL, но я всегда включаю (:use :common-lisp) в свои пакеты. Документация Common Lisp HyperSpe c defpackage гласит: Если :use не указано, по умолчанию используется то же значение, зависящее от реализации, что и аргумент :use для make-package. Здесь вы можете увидеть разницу между CMUCL и SBCL:

CMUCL


CL-USER> ;; CMUCL
; No value
CL-USER> (defpackage :new)
#<The NEW package, 0/9 internal, 0/2 external>
CL-USER> (package-use-list :new)
(#<The COMMON-LISP package, 0/6 internal, 978/1227 external>)

SBCL


CL-USER> ;; SBCL
; No value
CL-USER> (defpackage :new)
#<PACKAGE "NEW">
CL-USER> (package-use-list :new)
NIL

Функция package-use-list показывает, что new пакет использует common-lisp в CMUCL, но не в SBCL. Вы можете избежать таких проблем, явно use ing пакетов:

CL-USER> (defpackage :new (:use :common-lisp))
#<PACKAGE "NEW">
CL-USER> (package-use-list :new)
(#<PACKAGE "COMMON-LISP">)
CL-USER> (in-package :new)
#<PACKAGE "NEW">
NEW> (+ 2 2)
4

В файле обычно используется :export в форме defpackage для экспорта символов, но из REPL в В пакете new вы также можете определить функции и экспортировать их символы для использования в других пакетах:

NEW> (defun add3 (x) (+ x 3))
ADD3
NEW> (export 'add3)
T

Затем go вернитесь в основное рабочее пространство, пакет common-lisp-user и вызовите use-package для получить доступ к новой функции:

NEW> (in-package :cl-user)
#<PACKAGE "COMMON-LISP-USER">
CL-USER> (use-package :new)
T
CL-USER> (add3 4)
7
0 голосов
/ 23 апреля 2020

Это дополнение к другим ответам.

Одна вещь, которую я делал в прошлом, - это написать макрос так:

(defvar *user-package-use-list*
  (package-use-list (find-package ':common-lisp-user)))

(defmacro define-user-package (name &body options)
  `(defpackage ,name
     (:use ,@(mapcar #'package-name *user-package-use-list*))
     ,@options))

Используя это затем

(define-user-package :my-user-package)

Будет определять пакет, который «похож» на CL-USER в том смысле, что он использует все те же пакеты, и он будет делать это так, чтобы он работал в разных реализациях.

...