racket/collects/scribblings/guide/module-languages.scrbl
Eli Barzilay ac26fe7554 A ton of @scheme*' -> @racket*' and related updates.
Also, updates some of the mzlib files to point at `racket/*' libraries
rather than to `scheme/*' ones.
2011-06-25 04:08:47 -04:00

182 lines
6.0 KiB
Racket

#lang scribble/doc
@(require scribble/manual scribble/eval "guide-utils.rkt" "modfile.rkt"
(for-label racket/date))
@title[#:tag "module-languages"]{Module Languages}
When using the longhand @racket[module] form for writing modules, the
module path that is specified after the new module's name provides the
initial imports for the module. Since the initial-import module
determines even the most basic bindings that are available in a
module's body, such as @racket[require], the initial import can be
called a @deftech{module language}.
The most common @tech{module languages} are @racketmodname[racket] or
@racketmodname[racket/base], but you can define your own
@tech{module language} by defining a suitable module. For example,
using @racket[provide] subforms like @racket[all-from-out],
@racket[except-out], and @racket[rename-out], you can add, remove, or
rename bindings from @racketmodname[racket] to produce a @tech{module
language} that is a variant of @racketmodname[racket]:
@guideother{@secref["module-syntax"] introduces the longhand
@racket[module] form.}
@interaction[
(module raquet racket
(provide (except-out (all-from-out racket) lambda)
(rename-out [lambda function])))
(module score 'raquet
(map (function (points) (case points
[(0) "love"] [(1) "fifteen"]
[(2) "thirty"] [(3) "forty"]))
(list 0 2)))
(require 'score)
]
@; ----------------------------------------
@section[#:tag "implicit-forms"]{Implicit Form Bindings}
If you try to remove too much from @racketmodname[racket] in defining
your own @tech{module language}, then the resulting module
will no longer work right as a @tech{module language}:
@interaction[
(module just-lambda racket
(provide lambda))
(module identity 'just-lambda
(lambda (x) x))
]
The @racket[#%module-begin] form is an implicit form that wraps the
body of a module. It must be provided by a module that is to be used
as @tech{module language}:
@interaction[
(module just-lambda racket
(provide lambda #%module-begin))
(module identity 'just-lambda
(lambda (x) x))
(require 'identity)
]
The other implicit forms provided by @racket[racket/base] are
@racket[#%app] for function calls, @racket[#%datum] for literals, and
@racket[#%top] for identifiers that have no binding:
@interaction[
(module just-lambda racket
(provide lambda #%module-begin
(code:comment @#,t{@racketidfont{ten} needs these, too:})
#%app #%datum))
(module ten 'just-lambda
((lambda (x) x) 10))
(require 'ten)
]
Implicit forms such as @racket[#%app] can be used explicitly in a module,
but they exist mainly to allow a module language to restrict or change
the meaning of implicit uses. For example, a @racket[lambda-calculus]
@tech{module language} might restrict functions to a single argument,
restrict function calls to supply a single argument, restrict the
module body to a single expression, disallow literals, and treat
unbound identifiers as uninterpreted symbols:
@interaction[
(module lambda-calculus racket
(provide (rename-out [1-arg-lambda lambda]
[1-arg-app #%app]
[1-form-module-begin #%module-begin]
[no-literals #%datum]
[unbound-as-quoted #%top]))
(define-syntax-rule (1-arg-lambda (x) expr)
(lambda (x) expr))
(define-syntax-rule (1-arg-app e1 e2)
(#%app e1 e2))
(define-syntax-rule (1-form-module-begin e)
(#%module-begin e))
(define-syntax (no-literals stx)
(raise-syntax-error #f "no" stx))
(define-syntax-rule (unbound-as-quoted . id)
'id))
(module ok 'lambda-calculus
((lambda (x) (x z))
(lambda (y) y)))
(require 'ok)
(module not-ok 'lambda-calculus
(lambda (x y) x))
(module not-ok 'lambda-calculus
(lambda (x) x)
(lambda (y) (y y)))
(module not-ok 'lambda-calculus
(lambda (x) (x x x)))
(module not-ok 'lambda-calculus
10)
]
Module languages rarely redefine @racket[#%app], @racket[#%datum], and
@racket[#%top], but redefining @racket[#%module-begin] is more
frequently useful. For example, when using modules to construct
descriptions of HTML pages where a description is exported from the
module as @racketidfont{page}, an alternate @racket[#%module-begin]
can help eliminate @racket[provide] and quasiquoting
boilerplate, as in @filepath{html.rkt}:
@racketmodfile["html.rkt"]
Using the @filepath{html.rkt} @tech{module language}, a simple web page
can be described without having to explicitly define or export
@racketidfont{page} and starting in @racket[quasiquote]d mode instead
of expression mode:
@interaction[
(module lady-with-the-spinning-head "html.rkt"
(title "Queen of Diamonds")
(p "Updated: " ,(now)))
(require 'lady-with-the-spinning-head)
page
]
@; ----------------------------------------
@section[#:tag "s-exp"]{Using @racket[@#,hash-lang[] @#,racketmodname[s-exp]]}
Implementing a language at the level of @hash-lang[] is more complex
than declaring a single module, because @hash-lang[] lets programmers
control several different facets of a language. The
@racketmodname[s-exp] language, however, acts as a kind of
meta-language for using a @tech{module language} with the
@hash-lang[] shorthand:
@racketmod[
s-exp _module-name
_form ...]
is the same as
@racketblock[
(module _name _module-name
_form ...)
]
where @racket[_name] is derived from the source file containing the
@hash-lang[] program. The name @racketmodname[s-exp] is short for
``@as-index{S-expression},'' which is a traditional name for
Racket's @tech{reader}-level lexical conventions: parentheses,
identifiers, numbers, double-quoted strings with certain backslash
escapes, and so on.
Using @racket[@#,hash-lang[] @#,racketmodname[s-exp]], the
@racket[lady-with-the-spinning-head] example from before can be
written more compactly as:
@racketmod[
s-exp "html.rkt"
(title "Queen of Diamonds")
(p "Updated: " ,(now))
]
Later in this guide, @secref["hash-languages"] explains how to define
your own @hash-lang[] language, but first we explain how you can write
@tech{reader}-level extensions to Racket.