
--- but Gwyth's amazingly helpful review of chapters 1-11 pointed out a few problems that are more difficult to fix and are still pending
148 lines
5.2 KiB
Racket
148 lines
5.2 KiB
Racket
#lang scribble/doc
|
|
@(require "mz.ss"
|
|
(for-label racket/package))
|
|
|
|
@(define pack-eval (make-base-eval))
|
|
@interaction-eval[#:eval pack-eval (require racket/package)]
|
|
|
|
@title[#:tag "package"]{Limiting Scope: @racket[define-package], @racket[open-package], ...}
|
|
|
|
@note-lib-only[racket/package]
|
|
|
|
@deftogether[(
|
|
@defform[(define-package package-id exports form ...)]
|
|
@defform/subs[(open-package package-id)
|
|
([exports (id ...)
|
|
(code:line #:only (id ...))
|
|
#:all-defined
|
|
(code:line #:all-defined-except (id ...))])]
|
|
)]{
|
|
|
|
@margin-note{The @racket[define-package] form is based on the @racketidfont{module}
|
|
form of Chez Scheme @cite["Waddell99"].}
|
|
|
|
The @racket[define-package] form is similar to @racket[module], except
|
|
that it can appear in any definition context. The @racket[form]s
|
|
within a @racket[define-package] form can be definitions or
|
|
expressions; definitions are not visible outside the
|
|
@racket[define-package] form, but @racket[exports] determines a subset
|
|
of the bindings that can be made visible outside the package using
|
|
the definition form @racket[(open-package package-id)].
|
|
|
|
The @racket[(id ...)] and @racket[#:only (id ...)] @racket[exports]
|
|
forms are equivalent: exactly the listed @racket[id]s are
|
|
exported. The @racket[#:all-defined] form exports all definitions from
|
|
the package body, and @racket[#:all-defined-except (id ...)] exports
|
|
all definitions except the listed @racket[id]s.
|
|
|
|
All of the usual definition forms work within a
|
|
@racket[define-package] body, and such definitions are visible to all
|
|
expressions within the body (and, in particular, the definitions can
|
|
refer to each other). However, @racket[define-package] handles
|
|
@racket[define*], @racket[define*-syntax], @racket[define*-values],
|
|
@racket[define*-syntaxes], and
|
|
@racket[open*-package] specially: the bindings introduced by those
|
|
forms within a @racket[define-package] body are visible only to
|
|
@racket[form]s that appear later in the body, and they can shadow any
|
|
binding from preceding @racket[form]s (even if the preceding binding
|
|
did not use one of the special @racketidfont{*} definition forms). If
|
|
an exported identifier is defined multiple times, the last definition
|
|
is the exported one.
|
|
|
|
@examples[
|
|
#:eval pack-eval
|
|
(define-package presents (doll)
|
|
(define doll "Molly Coddle")
|
|
(define robot "Destructo"))
|
|
doll
|
|
robot
|
|
(open-package presents)
|
|
doll
|
|
robot
|
|
(define-package big-russian-doll (middle-russian-doll)
|
|
(define-package middle-russian-doll (little-russian-doll)
|
|
(define little-russian-doll "Anastasia")))
|
|
(open-package big-russian-doll)
|
|
(open-package middle-russian-doll)
|
|
little-russian-doll
|
|
]}
|
|
|
|
|
|
@defform[(package-begin form ...)]{
|
|
|
|
Similar to @racket[define-package], but it only limits the visible of
|
|
definitions without binding a package name. If the last @racket[form]
|
|
is an expression, then the expression is in @tech{tail position} for
|
|
the @racket[package-begin] form, so that its result is the
|
|
@racket[package-begin] result.
|
|
|
|
A @racket[package-begin] form can be used as an expression, but if it
|
|
is used in a context where definitions are allowed, then the
|
|
definitions are essentially spliced into the enclosing context (though
|
|
the defined bindings remain hidden outside the
|
|
@racket[package-begin]).
|
|
|
|
@examples[
|
|
#:eval pack-eval
|
|
(package-begin
|
|
(define secret "mimi")
|
|
(list secret))
|
|
secret
|
|
]}
|
|
|
|
@deftogether[(
|
|
@defidform[define*]
|
|
@defidform[define*-values]
|
|
@defidform[define*-syntax]
|
|
@defidform[define*-syntaxes]
|
|
@defidform[open*-package]
|
|
)]{
|
|
|
|
Equivalent to @racket[define], @racket[define-values],
|
|
@racket[define-syntax], @racket[define-syntaxes],
|
|
and @racket[open-package], except within a
|
|
@racket[define-package] or @racket[package-begin] form, where they
|
|
create bindings that are visible only to later body forms.
|
|
|
|
@examples[
|
|
#:eval pack-eval
|
|
(define-package mail (cookies)
|
|
(define* cookies (list 'sugar))
|
|
(define* cookies (cons 'chocolate-chip cookies)))
|
|
(open-package mail)
|
|
cookies
|
|
(define-syntax-rule (define-seven id) (define id 7))
|
|
(define-syntax-rule (define*-seven id)
|
|
(begin
|
|
(define-package p (id) (define-seven id))
|
|
(open*-package p)))
|
|
(package-begin
|
|
(define vii 8)
|
|
(define*-seven vii)
|
|
vii)]}
|
|
|
|
@deftogether[(
|
|
@defproc[(package? [v any/c]) boolean?]
|
|
@defproc[(package-exported-identifiers [id identifier?]) (listof identifier?)]
|
|
@defproc[(package-original-identifiers [id identifier?]) (listof identifier?)]
|
|
)]{
|
|
|
|
The @racket[package?], @racket[package-exported-identifiers], and
|
|
@racket[package-original-identifiers] functions are exported
|
|
@racket[for-syntax] by @racketmodname[racket/package].
|
|
|
|
The @racket[package?] predicate returns @racket[#t] if @racket[v] is a
|
|
package value as obtained by @racket[syntax-local-value] on an
|
|
identifier that is bound to a package.
|
|
|
|
Given such an identifier, the @racket[package-exported-identifiers]
|
|
function returns a list of identifiers that correspond to the
|
|
bindings that would be introduced by opening the package in the
|
|
lexical context being expanded. The
|
|
@racket[package-original-identifiers] function returns a parallel list
|
|
of identifiers for existing bindings of package's exports.}
|
|
|
|
@; ----------------------------------------------------------------------
|
|
|
|
@close-eval[pack-eval]
|