namespace and may also cause problems later if you try to use the package. [228]

To read code in this package, you need to make it the current package with the IN- PACKAGE macro:

(in-package :com.gigamonkeys.email-db)

If you type this expression at the REPL, it will change the value of *PACKAGE*, affecting how the REPL reads subsequent expressions, until you change it with another call to IN-PACKAGE. Similarly, if you include an IN-PACKAGE in a file that's loaded with LOAD or compiled with COMPILE-FILE, it will change the package, affecting the way subsequent expressions in the file are read.[229]

With the current package set to the COM.GIGAMONKEYS.EMAIL-DB package, other than names inherited from the COMMON-LISP package, you can use any name you want for whatever purpose you want. Thus, you could define a new hello-world function that could coexist with the hello-world function previously defined in COMMON-LISP-USER. Here's the behavior of the existing function:

CL-USER> (hello-world)

hello, world

NIL

Now you can switch to the new package using IN-PACKAGE.[230] Notice how the prompt changes—the exact form is determined by the development environment, but in SLIME the default prompt consists of an abbreviated version of the package name.

CL-USER> (in-package :com.gigamonkeys.email-db)

#<The COM.GIGAMONKEYS.EMAIL-DB package>

EMAIL-DB>

You can define a new hello-world in this package:

EMAIL-DB> (defun hello-world () (format t 'hello from EMAIL-DB package~%'))

HELLO-WORLD

And test it, like this:

EMAIL-DB> (hello-world)

hello from EMAIL-DB package

NIL

Now switch back to CL-USER.

EMAIL-DB> (in-package :cl-user)

#<The COMMON-LISP-USER package>

CL-USER>

And the old function is undisturbed.

CL-USER> (hello-world)

hello, world

NIL

Packaging Reusable Libraries

While working on the e-mail database, you might write several functions related to storing and retrieving text that don't have anything in particular to do with e-mail. You might realize that those functions could be useful in other programs and decide to repackage them as a library. You should define a new package, but this time you'll export certain names to make them available to other packages.

(defpackage :com.gigamonkeys.text-db

(:use :common-lisp)

(:export :open-db

:save

:store))

Again, you use the COMMON-LISP package, because you'll need access to standard functions within COM.GIGAMONKEYS.TEXT-DB. The :export clause specifies names that will be external in COM.GIGAMONKEYS.TEXT-DB and thus accessible in packages that :use it. Therefore, after you've defined this package, you can change the definition of the main application package to the following:

(defpackage :com.gigamonkeys.email-db

(:use :common-lisp :com.gigamonkeys.text-db))

Now code written in COM.GIGAMONKEYS.EMAIL-DB can use unqualified names to refer to the exported symbols from both COMMON-LISP and COM.GIGAMONKEYS.TEXT-DB. All other names will continue to be interned directly in the COM.GIGAMONKEYS.EMAIL-DB package.

Importing Individual Names

Now suppose you find a third-party library of functions for manipulating e-mail messages. The names used in the library's API are exported from the package COM.ACME.EMAIL, so you could :use that package to get easy access to those names. But suppose you need to use only one function from this library, and other exported symbols conflict with names you already use (or plan to use) in our own code.[231] In this case, you can import the one symbol you need with an :import-from clause in the DEFPACKAGE. For instance, if the name of the function you want to use is parse-email-address, you can change the DEFPACKAGE to this:

(defpackage :com.gigamonkeys.email-db

(:use :common-lisp :com.gigamonkeys.text-db)

(:import-from :com.acme.email :parse-email-address))

Now anywhere the name parse-email-address appears in code read in the COM.GIGAMONKEYS.EMAIL-DB package, it will be read as the symbol from COM.ACME.EMAIL. If you need to import more than one symbol from a single package, you can include multiple names after the package name in a single :import-from clause. A DEFPACKAGE can also include multiple :import-from clauses in order to import symbols from different packages.

Occasionally you'll run into the opposite situation—a package may export a bunch of names you want to use and a few you don't. Rather than listing all the symbols you do want to use in an :import-from clause, you can instead :use the package and then list the names you don't want to inherit in a :shadow clause. For instance, suppose the COM.ACME.TEXT package exports a bunch of names of functions and classes used in text processing. Further suppose that most of these functions and classes are ones you'll want to use in your code, but one of the names, build-index, conflicts with a name you've already used. You can make the build-index from COM.ACME.TEXT inaccessible by shadowing it.

(defpackage :com.gigamonkeys.email-db

(:use

Вы читаете Practical Common Lisp
Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

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

Отметить Добавить цитату