2013-09-08 2 views
1

Я хочу использовать некоторые функции внутри другого пакета с длинным именем (например, «SB-BSD-сокеты»), и я должен написать это:Common Lisp: Как импортировать символы других пакетов только в лексической области?

(defun myfun (...) 
    (sb-bsd-sockets:socket-bind ...) 
    (sb-bsd-sockets:socket-listen ...) 
    ...) 

Есть ли способ, чтобы импортировать некоторые из тех, символы доступны только внутри myfun (без каких-либо потерь производительности)? не

ответ

2

Первое, что появилось в моей голове (простая прогулка по дереву и замена имен символов).

Следует отметить, что вопрос был о , импортируя символы, и следующее не делает этого. Он просто добавляет уродливое имя пакета :: part для вас. Пример

(defmacro with-symbols-from ((package-name &rest symbols) &body body) 
    (let ((f-symbols (loop :for s :in symbols :collect 
         (intern (symbol-name s) package-name)))) 
    `(progn 
     ,@(loop :for symbol :in symbols :for f-symbol :in f-symbols 
      :with body = body 
      :do (setf body (subst f-symbol symbol body :test #'eq)) 
      :finally (return body))))) 

Использование:

CL-USER> (with-symbols-from (:cffi foreign-alloc mem-aref) 
      (let ((a (foreign-alloc :int))) 
      (setf (mem-aref a :int) 1) 
      (mem-aref a :int))) 
1 

выше расширена:

(PROGN 
(LET ((A (CFFI:FOREIGN-ALLOC :INT))) 
    (SETF (CFFI:MEM-AREF A :INT) 1) 
    (CFFI:MEM-AREF A :INT))) 
1

Внутри функция, нет: defun формы в текущем *package*read, а символы в ней будут решены до того что-нибудь еще (внутри нее) обрабатываются.

Однако, вы можете сделать что-то вроде этого (непроверенные и не рекомендуется):

Вообще говоря, это не очень хорошая идея.

Было бы намного проще переместить код сокета в отдельный файл с отдельным пакетом, а затем использовать этот пакет в других файлах.

+0

Спасибо. и еще один вопрос: существует ли способ использования временного псевдонима для пакета? – SaltyEgg

+0

Вы можете использовать 'defpackage' для изменения списка псевдонимов. – sds

2

вопрос, который сразу приходит на ум, это "почему вы хотите сделать это?"

Я бы, как правило, просто импортировал пакет в (конкретный проект) пакет, который ему нужен, и/или структурировал мое дерево пакетов проектов, чтобы, если я абсолютно не могу иметь пакет B, импортированный в пакет A, A-sub, который импортирует его, экспортирует несколько функций, затем вызывает функцию A-sub: из другого кода в пакете A.

Как правило, если вы пытаетесь сделать что-то, что кажется неудобным в Common Lisp, это вероятно, время, чтобы сделать короткий шаг назад и подумать, что то, что вы пытаетесь сделать, - это лучший способ выполнить то, что вы хотите (в этом случае вопрос может быть «имеет значение, если символ socket-bind импортирован из sb-bsd -sockets? ", и если ответ не является громким ДА, то просто импортируйте сокет- связать в свой пакет).

+0

hmm, я хочу использовать некоторые функции 'sb-bsd-sockets' в одной или двух моих функциях, и я не хочу раскрывать вещи' socket-xxx' для других частей моего кода, чтобы предотвратить конфликты имен. Я не хочу решения A-sub, потому что есть только одна или две функции, которые нуждаются в 'socket-xxx'. Теперь мое решение - '(defpackage #: tmp (: use #: sb-bsd-sockets #: others)), а затем вместо него использовать' tmp :: socket-xxx' и, наконец, '(delete-package #: tmp) '. Это тоже не очень приятно. – SaltyEgg

+1

@SaltyEgg Если у вас возникли конфликты имен, вы всегда можете скрыть эти символы при импорте. Вам не нужно судорожно себя вести, пока в этом нет необходимости. – Vatine

+0

OK, Спасибо ~~~~~ – SaltyEgg