2012-04-11 24 views
7

Sono un principiante Lisp che cerca di capire come usare correttamente il sistema di pacchetti Lisp mentre imparo LTK per la programmazione della GUI, usando SBCL 1.0.55.0.debian e Limp 0.3.4 (e Debian Wheezy se questo è importante). Ho installato ASDF utilizzando aptitude package manager (pacchetti cl-asdf & cl-common-lisp-controller), quindi ho installato Quicklisp utilizzando le istruzioni sul sito Web Quicklisp (http://www.quicklisp.org/beta/index.html) (non dal repository Debian) e quindi ho installato LTK con (ql:quickload 'ltk) nella console SBCL.Modo corretto di definire i pacchetti usando asdf: defsystem e quickproject

ciao-1.lisp (direttamente da LTK tutorial):

(defun hello-1() 
    (with-ltk() 
       (let ((b (make-instance ’button 
             :master nil 
             :text "Press Me" 
             :command (lambda() 
                 (format t "Hello World!~&"))))) 
        (pack b)))) 

Se compilo questo diritto su una nuova immagine SBCL Lisp in, ottengo il messaggio che WITH-LTK e PACK sono funzioni non definite e 'BUTTON è variabile non definita.

Così, ho scoperto che ho bisogno di caricare 'ltk prima e poi utilizzare in-package .I per essere in grado di farlo funzionare, ho dovuto usare (ql:quickload 'ltk) e (in-package :ltk) in consolle SBCL. Tuttavia, ho ancora un messaggio di errore che 'BUTTON è una variabile non definita.

* (ql:quickload 'ltk) 
To load "ltk": 
    Load 1 ASDF system: 
    ltk 
; Loading "ltk" 

(LTK) 
* (in-package :ltk) 

#<PACKAGE "LTK"> 
* (compile-file "/home/user/code/lisp/hello-1.lisp") 

; caught WARNING: 
; undefined variable: ’BUTTON 
; 
; compilation unit finished 
; Undefined variable: 
;  ’BUTTON 
; caught 1 WARNING condition 

; /home/user/code/lisp/hello-1.fasl written 
; compilation finished in 0:00:00.009 
#P"/home/user/code/lisp/hello-1.fasl" 
T 
T 
* 

Poi, in quanto questo non ha funzionato come volevo, ho anche tentato di definire le mie definizioni di pacchetto in base alle risposte di un'altra domanda (Problems with ltk (common lisp)), blog di Xach "Fare un piccolo progetto Lisp con quickproject e Quicklisp " e Manuale ASDF (http://common-lisp.net/project/asdf/asdf/The-defsystem-form.html) utilizzando quickproject:make-project, ma senza successo. Attualmente ho i seguenti file:

package.lisp (compila in modo pulito se prima (ql:quickload 'ltk) SBCL REPL):

(defpackage :hello-world-ltk-system 
    (:use :cl :asdf :ltk)) 

ciao-mondo-ltk.asd (compila in modo pulito dopo aver prima compilato package.lisp):

(in-package :hello-world-ltk-system) 
(asdf:defsystem :hello-world-ltk 
    :serial t 
    :description "Describe hello-world-ltk here" 
    :author "Your Name <[email protected]>" 
    :license "Specify license here" 
    :depends-on (:cl :asdf :ltk) 
    :components ((:file "package") 
      (:file "hello-world-ltk"))) 

ciao-mondo-ltk.lisp (ottengo errore di compilazione The name "HELLO-WORLD-LTK" does not designate any package).

(require 'hello-world-ltk) 
(in-package :hello-world-ltk) 
(defun hello-world-1() 
    (with-ltk() 
      (let ((b (make-instance 'button 
            :master nil 
            :text "Press me!" 
            :command (lambda() 
                (format t "Hello world!~&"))))) 
       (pack b))))   

Quando tento di compilare questo ciao-mondo-ltk.lisp dopo aver compilato con successo package.lisp e ciao-mondo-ltk.asd (che tutti risiedono nella stessa directory) ottengo il seguente errore:

; compiling (IN-PACKAGE :HELLO-WORLD-LTK) 
debugger invoked on a SB-KERNEL:SIMPLE-PACKAGE-ERROR in thread 
#<THREAD "initial thread" RUNNING {10029A0FA3}>: 
    The name "HELLO-WORLD-LTK" does not designate any package. 

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. 

restarts (invokable by number or by possibly-abbreviated name): 
    0: [ABORT] Exit debugger, returning to top level. 

(SB-INT:%FIND-PACKAGE-OR-LOSE "HELLO-WORLD-LTK") 
0] 
(load "/home/user/code/lisp/hello-world-ltk/hello-world-ltk") 

debugger invoked on a SIMPLE-ERROR in thread 
#<THREAD "initial thread" RUNNING {10029A0FA3}>: 
    attempt to load an empty FASL file: 
    "/home/user/code/lisp/hello-world-ltk/hello-world-ltk.fasl" 

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. 

restarts (invokable by number or by possibly-abbreviated name): 
    0: [ABORT] Reduce debugger level (to debug level 1). 
    1:   Exit debugger, returning to top level. 

(SB-FASL::LOAD-AS-FASL 
#<SB-SYS:FD-STREAM 
    for "file /home/user/code/lisp/hello-world-ltk/hello-world-ltk.fasl" 
    {1005291233}> 
NIL 
#<unavailable argument>) 
0[2] 

Quindi, sto abbastanza perso qui con tutti i diversi modi per definire pacchetti, ASDF, Quicklisp, package.lisp, quickproject, asdf:defsystem, require e ql:quickload ... quickproject:make-project sembra essere molto promettente, ma io in realtà non lo fanno sapere cosa c'è ancora che non va nei miei file sorgente. Sto cercando una soluzione che dovrebbe gestire tutte le compilazioni e i caricamenti dei pacchetti preferibilmente in un unico comando per l'intero progetto e che dovrebbe essere estensibile anche per i progetti più grandi.

Grazie per tutto l'aiuto :)

+0

Questa non è una risposta, ma una possibile risorsa: ho trovato il [capitolo sulla confezione] (http://www.gigamonkeys.com/book/programming-in-the-large-packages-and-symbols.html) dal libro [Practical Common Lisp] (http://www.gigamonkeys.com/book/) per aiutarmi a capire meglio come funzionano queste cose. Forse sarà utile per te e/o per gli altri che trovano questa domanda, pure. – lindes

+0

Ho letto anche quel capitolo e lo trovo utile. Tuttavia, [Practical Common Lisp] (http://www.gigamonkeys.com/book/) non tratta i sistemi creati con 'asdf: defsystem' né l'uso di' quickproject'. La risposta di Vsevolod (sotto) mi ha aiutato a capire la differenza tra pacchetti e sistemi. – nrz

+0

in effetti, è solo di aiuto per capire il lato del pacchetto delle cose. Quindi solo una parte del puzzle. Sono contento che sia una parte utile, comunque, almeno. :) – lindes

risposta

9

Il primo problema nel codice è che si utilizza apostrofo () al posto di zecca ('). Ecco perché ottieni un errore variabile non definito, poiché ’button viene letto come nome variabile (non è quotato).

Ora per i pacchetti e . Un pacchetto è definito con defpackage ed è una raccolta di simboli, che vengono utilizzati dopo il modulo in-package all'interno di un file (o in una sessione interattiva). Un pacchetto ha simboli interni ed esterni (esportati), a cui è possibile accedere rispettivamente come package::internal-symbol e package:external-symbol. I pacchetti possono anche simboli import da altri pacchetti. Se si use-package, si importano tutti i suoi simboli esterni. Mentre in-package imposta il pacchetto corrente su quello specificato e inizia a definire i simboli al suo interno (e non è consigliabile eseguire tali operazioni in pacchetti di terze parti, come LTK). Quindi, se si desidera utilizzare LTK simboli, come with-ltk o button, non vi resta che sia use-packageLTK o importare questi simboli dal LTK nel modulo defpackage:

(defpackage :hello-world-ltk-system 
    (:use :cl) 
    (:import-from :ltk :with-ltk :button)) 

o semplicemente importare tutti LTK simboli (con use clausola) :

(defpackage :hello-world-ltk-system 
    (:use :cl :ltk)) 

Infine, sistemi e pacchetti sono totalmente UNIRE cose belle. Un sistema è un'istanza di una classe ASDF:SYSTEM, che contiene informazioni sui file fisici e le loro relazioni, in modo che possano essere compilati e caricati in modo appropriato. Per la tua applicazione ciao-mondo ti suggerirei di non preoccuparti dei sistemi per ora e di scrivere tutto il tuo codice in un unico file. Questo file dovrebbe iniziare con un modulo defpackage, seguito da in-package e quindi il resto del codice.

Quando questo file diventerà abbastanza grande, vedrete parti chiare al suo interno, è possibile scomporre quelle parti in file separati. Poi si dovrà creare un file di definizione di sistema, che sarà simile a questa:

(asdf:defsystem :hello-world 
    :depends-on (:ltk) 
    :serial t 
    :components ((:file "package") 
       (:file "first") 
       (:file "second") 
       ...)) 

Il file "package.lisp" questo punto tenere la definizione del pacchetto.

+0

Ho spostato le definizioni del pacchetto sullo stesso hello-world-ltk.lisp insieme al resto dell'origine e definizioni dei pacchetti fissi, come suggerito e corretto le definizioni del pacchetto: '(defpackage: hello-world-ltk-system' ' (: use: cl) ' ' (: import-from: ltk: with-ltk: button: pack) ' ' (: export: hello-world-1)) ' ' (in pacchetto: ciao-world-ltk-system) ' Richiede ancora' (qt: quickload 'ltk) 'prima di compilarlo ma ora tutto funziona correttamente. Grazie per la risposta dettagliata. – nrz

+0

Sì, è vero. Ho dimenticato di menzionare che devi caricare in qualche modo le tue dipendenze (che sono sistemi) prima di caricare il tuo codice. Quindi devi inserire '(qt: quickload 'ltk)' all'inizio del tuo file. Lo stesso vale per altre dipendenze. Man mano che la tua applicazione crescerà e userai più librerie (che sono sistemi), avrai comunque un file di definizione '.asd', nel quale dovrai specificare tali dipendenze. –

+0

'(qt: quickload 'ltk)' non sembra funzionare, perché non viene valutato al momento della compilazione, ma funziona: '(eval-when (: compile-toplevel) (ql: quickload' ltk))' [link] (http://stackoverflow.com/questions/9832378/where-should-a-quicklisp-quickload-go-in-my-source-nowhere). Penso che questa sia una soluzione funzionante per test e piccoli progetti. – nrz