2012-03-16 18 views
8

Esiste un modo breve per esportare tutti i simboli da un pacchetto o è l'unico modo per farlo in defpackage. Io in genere scrivo il mio codice in un file foo.lisp che inizia in genere con (in-package :foo) e metto la definizione del pacchetto in un file package.lisp che coinvolge in genere qualcosa di simile:Comune Lisp che esporta i simboli dai pacchetti

(in-package :cl-user) 

(defpackage :foo 
    (:use :cl) 
    (:documentation "Bla bla bla." 
    (:export :*global-var-1* 
      :*global-var-2* 
      :function-1 
      :function-2 
      :struct 
      :struct-accessor-fun-1 
      :struct-accessor-fun-2 
      :struct-accessor-fun-3 
      :struct-accessor-fun-4)) 

La mia domanda è: Progettazione semplicemente un'interfaccia con alcune variabili globali e le funzioni potrebbero non essere adeguate a volte e devi esportare alcune strutture. In questo caso, se non si esportano semplicemente le funzioni di accesso di questa struttura, non è possibile manipolare oggetti di queste strutture. Quindi, esiste un modo semplice per realizzare questo effetto senza esportare manualmente tutte queste funzioni accessorie?

risposta

9

volta che il pacchetto è stato creato, e tutti i simboli in esso creati, ad esempio, caricando il codice che implementa il pacchetto, è possibile export qualsiasi simbolo che ti piace, ad esempio, di esportare tutti:

(do-all-symbols (sym (find-package :foo)) (export sym)) 

È Probabilmente sarà più felice con

(let ((pack (find-package :foo))) 
    (do-all-symbols (sym pack) (when (eql (symbol-package sym) pack) (export sym)))) 

che non tenterà di riesportare tutto da pacchetti usati.

4

Valutando il codice macroexpanded, ottengo un errore per l'ultimo nullo nel modulo defclass se non viene fornita alcuna opzione di classe e gli errori aggiuntivi come i simboli della funzione di esportazione devono essere citati. Ecco una versione corretta che sembra funzionare sul mio sistema Common Lisp (SBCL):

(defmacro def-exporting-class (name (&rest superclasses) (&rest slot-specs) 
           &optional class-option) 
    (let ((exports (mapcan (lambda (spec) 
          (when (getf (cdr spec) :export) 
          (let ((name (or (getf (cdr spec) :accessor) 
              (getf (cdr spec) :reader) 
              (getf (cdr spec) :writer)))) 
           (when name (list name))))) 
         slot-specs))) 
    `(progn 
     (defclass ,name (,@superclasses) 
     ,(append 
      (mapcar (lambda (spec) 
        (let ((export-pos (position :export spec))) 
         (if export-pos 
         (append (subseq spec 0 export-pos) 
          (subseq spec (+ 2 export-pos))) 
         spec))) 
       slot-specs) 
      (when class-option (list class-option)))) 
     ,@(mapcar (lambda (name) `(export ',name)) 
       exports)))) 


(macroexpand-1 
'(def-exporting-class test1 nil 
    ((test-1 :accessor test-1 :export t) 
    (test-2 :initform 1 :reader test-2 :export t) 
    (test-3 :export t)))) 

(PROGN 
(DEFCLASS TEST1 NIL 
      ((TEST-1 :ACCESSOR TEST-1) (TEST-2 :INITFORM 1 :READER TEST-2) 
      (TEST-3))) 
(EXPORT 'TEST-1) 
(EXPORT 'TEST-2)) 
+0

Davvero bello! Non avrei mai pensato di aggiungere e utilizzare uno slot (: export) nella definizione di slot CLOS standard. –

3

post di Vsevolod mi ha spinto a pubblicare una macro così:

(defmacro defpackage! (package &body options) 
    (let* ((classes (mapcan 
        (lambda (x) 
         (when (eq (car x) :export-from-classes) 
         (cdr x))) 
        options)) 
     (class-objs (mapcar #'closer-common-lisp:find-class classes)) 
     (class-slots (mapcan #'closer-mop:class-slots class-objs)) 
     (slot-names (mapcar #'closer-mop:slot-definition-name class-slots)) 
     (slots-with-accessors 
      (remove-duplicates (remove-if-not #'fboundp slot-names)))) 
    (setf options (mapcar 
        (lambda (option) 
         (if (eq (car option) :export) 
         (append option 
           (mapcar #'symbol-name slots-with-accessors)) 
         option)) 
        options)) 
    (setf options (remove-if 
        (lambda (option) 
         (eq (car option) :export-from-classes)) 
        options)) 
    `(defpackage ,package ,@options))) 

Per utilizzare:

CL-USER> 
(defclass test-class() 
    ((amethod :accessor amethod :initarg :amethod :initform 0) 
    (bmethod :reader bmethod :initform 1))) 
#<STANDARD-CLASS TEST-CLASS> 
CL-USER> 
(closer-mop:ensure-finalized (find-class 'test-class)) 
#<STANDARD-CLASS TEST-CLASS> 
CL-USER> 
(macroexpand-1 
    `(defpackage! test-package 
    (:export "symbol1") 
    (:export-from-classes test-class))) 
(DEFPACKAGE TEST-PACKAGE 
    (:EXPORT "symbol1" "AMETHOD" "BMETHOD")) 
T 
CL-USER> 

Questo non è ben testato, e sto ancora imparando l'API MOP, quindi potrebbero esserci modi molto migliori/più puliti per raggiungere lo stesso obiettivo qui (in particolare il fboundp kludge). Inoltre, questo cerca solo le funzioni accessorie su una classe. Esistono anche metodi specializzati in una classe. È possibile utilizzare il MOP per trovare anche quelli ...

Problemi correlati