start scribbling mzlib (about half done)

svn: r8546
This commit is contained in:
Matthew Flatt 2008-02-05 22:07:35 +00:00
parent f3bbc44451
commit 8bac4b1d28
32 changed files with 1914 additions and 206 deletions

View File

@ -2,3 +2,4 @@
(define name "Graphics documentation")
(define scribblings '(("graphics.scrbl" (multi-page))))
(define doc-categories '(legacy))

View File

@ -1,164 +1,4 @@
#lang scheme/base
(module async-channel mzscheme
(require (lib "etc.ss")
(lib "contract.ss"))
;; This library implements buffered channels with
;; and optional buffer limit (so that puts block
;; if the buffer is full).
;; We make a fancy structure just so an async-channel
;; can be supplied directly to `sync'.
;; The alternative is to use `define-struct' and supply
;; a `async-channel-get-evt' procedure.
(define-values (struct:ac make-ac async-channel? ac-ref ac-set!)
(make-struct-type 'async-channel #f 5 0 #f
(list (cons prop:evt
;; This is the guard that is called when
;; we use an async-channel as an event
;; (to get).
(lambda (ac)
(async-channel-get-guard ac))))
(current-inspector) #f))
(define ac-enqueue-ch (make-struct-field-accessor ac-ref 0))
(define ac-dequeue-ch (make-struct-field-accessor ac-ref 1))
(define ac-empty-ch (make-struct-field-accessor ac-ref 2))
(define ac-full-ch (make-struct-field-accessor ac-ref 3))
(define ac-thread (make-struct-field-accessor ac-ref 4))
;; Make ----------------------------------------
(define make-async-channel
(opt-lambda ([limit #f])
(let* ([enqueue-ch (make-channel)] ; for puts
[dequeue-ch (make-channel)] ; for gets
[empty-ch (make-channel)] ; for get polls
[full-ch (make-channel)] ; for put polls
[queue-first (mcons #f null)] ; queue head
[queue-last queue-first] ; queue tail
[size 0] ; queue size
;; Events:
[tell-empty
(channel-put-evt empty-ch (make-semaphore))] ; see poll->ch
[tell-full
(channel-put-evt full-ch (make-semaphore))] ; see poll->ch
[enqueue (handle-evt
enqueue-ch
(lambda (v)
;; We received a put; enqueue it:
(let ([p (mcons #f null)])
(set-mcar! queue-last v)
(set-mcdr! queue-last p)
(set! queue-last p)
(set! size (add1 size)))))]
[mk-dequeue
(lambda ()
(handle-evt
(channel-put-evt dequeue-ch (mcar queue-first))
(lambda (ignored)
;; A get succeeded; dequeue it:
(set! size (sub1 size))
(set! queue-first (mcdr queue-first)))))]
[manager-thread
;; This thread is the part that makes the channel asynchronous.
;; It waits for a combination of gets and puts as appropriate.
;; Note that we start it with `thread/suspend-kill', and we
;; resume the manager thread with the current thread everytime
;; we want to talk to the manager thread, which effectively
;; means that the manager thread is not bound by a custodian
;; that is weaker than any of its user's custodians (and thus,
;; from the user's perspective, is not bound by any custodian
;; at all).
(thread/suspend-to-kill
(lambda ()
(let loop ()
(cond
[(zero? size)
;; The queue is currently empty:
(sync enqueue tell-empty)]
[(or (not limit) (size . < . limit))
(sync enqueue (mk-dequeue))]
[else
(sync (mk-dequeue) tell-full)])
(loop))))])
(make-ac enqueue-ch dequeue-ch empty-ch full-ch manager-thread))))
;; Get ----------------------------------------
(define (async-channel-get-guard ac)
;; Make sure queue manager is running:
(thread-resume (ac-thread ac) (current-thread))
;; If it the channel is being polled, it's not
;; good enough to poll the dequeue channel, because
;; the server thread may be looping. In that case,
;; block on the dequeue channel and the empty
;; channel, and create a new waitable to report
;; the result.
(poll-guard-evt
(lambda (poll?)
(if poll?
(poll->ch (ac-dequeue-ch ac) (ac-empty-ch ac))
(ac-dequeue-ch ac)))))
(define (async-channel-get ac)
(sync ac))
(define (async-channel-try-get ac)
(sync/timeout 0 ac))
;; Put ----------------------------------------
(define (async-channel-put-evt ac v)
(letrec ([p (wrap-evt
(guard-evt
(lambda ()
;; Make sure queue manager is running:
(thread-resume (ac-thread ac) (current-thread))
(let ([p (channel-put-evt (ac-enqueue-ch ac) v)])
;; Poll handling, as in `async-channel-get-guard':
(poll-guard-evt
(lambda (poll?)
(if poll?
(poll->ch p (ac-full-ch ac))
p))))))
(lambda (ignored) p))])
p))
(define (async-channel-put ac v)
(thread-resume (ac-thread ac) (current-thread))
(sync (channel-put-evt (ac-enqueue-ch ac) v))
(void))
;; Poll helper ----------------------------------------
(define (poll->ch normal not-ready)
(sync
;; If a value becomes available,
;; create a waitable that returns
;; the value:
(wrap-evt
normal
(lambda (v)
;; Return a waitable for a successful poll:
(wrap-evt
always-evt
(lambda (ignored) v))))
;; If not-ready becomes available,
;; the result is supposed to be
;; a never-ready waitable:
not-ready))
;; Provides ----------------------------------------
(provide async-channel?)
(provide/contract (make-async-channel (case->
(-> async-channel?)
((union false/c (lambda (x)
(and (integer? x)
(exact? x)
(positive? x))))
. -> . async-channel?)))
(async-channel-get (async-channel? . -> . any/c))
(async-channel-try-get (async-channel? . -> . any/c))
(async-channel-put (async-channel? any/c . -> . any/c))
(async-channel-put-evt (async-channel? any/c . -> . evt?))))
(require scheme/async-channel)
(provide (all-from-out scheme/async-channel))

View File

@ -430,6 +430,9 @@
(subset?-helper (integer-set-contents s1) (integer-set-contents s2)))
(define int (flat-named-contract "exact-integer" int?))
(provide well-formed-set?)
(provide/contract (struct integer-set ((contents (flat-named-contract "integer-set-list" well-formed-set?))))
(make-range (case-> (-> integer-set?)
(int . -> . integer-set?)

View File

@ -0,0 +1,69 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/awk
scheme/contract))
@mzlib[#:mode title awk]
@defform/subs[
#:literals (after range / => :range range: :range: else)
(awk next-record-expr
(record field-id ...)
maybe-counter
((state-variable init-expr) ...)
maybe-continue
clause ...)
([maybe-counter code:blank
id]
[maybe-continue code:blank
id]
[clause (test body ...+)
(test => procedure-expr)
(/ regexp-str / (id-or-false ...+) body ...+)
(range excl-start-test excl-stop-test body ...+)
(:range incl-start-test excl-stop-test body ...+)
(range: excl-start-test incl-stop-test body ...+)
(:range: incl-start-test incl-stop-test body ...+)
(else body ...+)
(after body ...+)]
[test integer
regexp-string
expr]
[excl-start-test test]
[excl-stop-test test]
[incl-start-test test]
[incl-stop-test test]
[id-or-false id
#f])]{
The @scheme[awk] macro from Scsh @cite["Shivers06"]. In addition to
@scheme[awk], the Scsh-compatible procedures @scheme[match:start],
@scheme[match:end], @scheme[match:substring], and @scheme[regexp-exec]
are defined. These @schemeidfont{match:} procedures must be used to
extract match information in a regular expression clause when using
the @scheme[=>] form. }
@deftogether[(
@defproc[(match:start [rec ....]
[which exact-nonnegative-integer? 0])
exact-nonnegative-integer?]
@defproc[(match:end [rec ....]
[which exact-nonnegative-integer? 0])
exact-nonnegative-integer?]
@defproc[(match:substring
[rec ....]
[which exact-nonnegative-integer? 0])
string?]
)]{
Extracts a start position, end position, or substring corresponding to
a match. The first argument is the value supplied to the procedure
after @scheme[=>] in a @scheme[awk] clause or the result of
@scheme[regexp-exec].}
@defproc[(regexp-exec [re (or/c string? regexp?)] [s string?])
(or/c .... false/c)]{
Matches a regexp to a string, returning a record compatible with
@scheme[match:start], etc.}

View File

@ -0,0 +1,83 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/class100
mzlib/class
scheme/contract))
@mzlib[#:mode title class100]
The @scheme[class100] and @scheme[class100*] forms provide a syntax
close to that of @scheme[class] and @scheme[class*] in PLT Scheme
versions 100 through 103, but with the semantics of the current
@schememodname[scheme/class]-based class system. For a class defined
with @scheme[class100], keyword-based initialization arguments can be
propagated to the superclass, but by-position arguments are not (i.e.,
the expansion of @scheme[class100] to @scheme[class] always includes
an @scheme[init-rest] clause).
The @scheme[class100] form uses keywords (e.g., @scheme[public]) that
are defined by the @schememodname[mzlib/class] library, so typically
@schememodname[scheme/class] must be imported into any context that
imports @schememodname[mzlib/class100].
@defform/subs[
#:literals (sequence public override augment pubment
overment augride private private-field inherit
rename)
(class100* superclass-expr (interface-expr ...) init-ids
class100-clause
...)
([init-ids id
(id ... id-with-default ...)
(id ... id-with-default ... . id) ]
[id-with-default (id default-expr) ]
[class100-clause (sequence expr ...)
(public public-method-decl ...)
(override public-method-decl ...)
(augment public-method-decl ...)
(pubment public-method-decl ...)
(overment public-method-decl ...)
(augride public-method-decl ...)
(private private-method-decl ...)
(private-field private-var-decl ...)
(inherit inherit-method-decl ...)
(rename rename-method-decl ...) ]
[public-method-decl ((internal-id external-id) method-procedure)
(id method-procedure)]
[private-method-decl (id method-procedure)]
[private-var-decl (id initial-value-expr)
(id)
id]
[inherit-method-decl id
(internal-instance-id external-inherited-id)]
[rename-method-decl (internal-id external-id)])]
@defform[
(class100 superclass-expr init-ids
class100-clause
...)
]{
Like @scheme[class100*], but without @scheme[interface-expr]s.}
@defform[(class100-asi superclass instance-id-clause ...)]{
Like @scheme[class100], but all initialization arguments are
automatically passed on to the superclass initialization procedure by
position.}
@defform[(class100*-asi superclass interfaces instance-id-clause ...)]{
Like @scheme[class100*], but all initialization arguments are
automatically passed on to the superclass initialization procedure by
position.}
@defform[(super-init init-arg-expr ...)]{
An alias for @scheme[super-make-object].}

View File

@ -0,0 +1,38 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/cmdline))
@(define-syntax-rule (intro id)
(begin
(require (for-label scheme/cmdline))
(define id (scheme command-line))))
@(intro scheme-command-line)
@mzlib[#:mode title cmdline]
Provides a @scheme[command-line] from that is similar to the one in
@schememodname[scheme/cmdline], but without using keywords. The
@scheme[parse-command-line] procedure from
@schememodname[scheme/cmdline] is re-exported directly.
@defform/subs[
#:literals (multi once-each once-any final help-labels args =>)
(command-line program-name-expr argv-expr clause ...)
([clause (multi flag-spec ...)
(once-each flag-spec ...)
(once-any flag-spec ...)
(final flag-spec ...)
(help-labels string ...)
(args arg-formals body-expr ...+)
(=> finish-proc-expr arg-help-expr help-proc-expr
unknown-proc-expr)]
[flag-spec (flags id ... help-str ...+ body-expr ...+)
(flags => handler-expr help-expr)]
[flags flag-string
(flag-string ...+)]
[arg-formals id
(id ...)
(id ...+ . id)])]{
Like @scheme-command-line from @scheme[scheme/cmdline], but without
keywords in the syntax.}

View File

@ -0,0 +1,45 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/cml))
@mzlib[#:mode title cml]
The @schememodname[mzlib/cml] library defines a number of procedures
that wrap PLT Scheme concurrency procedures. The wrapper procedures
have names and interfaces that more closely match those of Concurrent
ML @cite["Reppy99"].
@defproc[(spawn [thunk (-> any)]) thread?]{
Equivalent to @scheme[(thread/suspend-to-kill thunk)].}
@defproc[(channel) channel?]{
Equivalent to @scheme[(make-channel)].}
@defproc[(channel-recv-evt [ch channel?]) evt?]{
Equivalent to @scheme[ch].}
@defproc[(channel-send-evt [ch channel?][v any/c]) evt?]{
Equivalent to @scheme[(channel-put-evt ch v)].}
@defproc[(thread-done-evt [thd thread?]) any]{
Equivalent to @scheme[(thread-dead-evt thread)].}
@defproc[(current-time) real?]{
Equivalent to @scheme[(current-inexact-milliseconds)].}
@defproc[(time-evt [tm real?]) evt?]{
Equivalent to @scheme[(alarm-evt tm)].}

View File

@ -0,0 +1,19 @@
#lang scheme/base
(require (for-syntax scheme/base)
scribble/manual
(for-label mzscheme))
(provide mzlib
(all-from-out scribble/manual)
(for-label (all-from-out mzscheme)))
(define-syntax (mzlib stx)
(syntax-case stx ()
[(_ #:mode section name)
(with-syntax ([lib (string->symbol
(format "mzlib/~a" (syntax-e #'name)))])
#'(begin
(section #:style 'hidden (scheme lib))
(defmodule lib)))]
[(_ name) #'(mzlib #:mode section name)]))

View File

@ -0,0 +1,96 @@
#lang scribble/doc
@(require "common.ss"
scribble/eval
(for-label mzlib/compat))
@(define compat-eval (make-base-eval))
@interaction-eval[#:eval compat-eval (require mzlib/compat)]
@mzlib[#:mode title compat]
The @schememodname[mzlib/compat] library defines a number of
procedures and syntactic forms that are commonly provided by other
Scheme implementations. Most of the procedures are aliases for
@schememodname[mzscheme] procedures.
@deftogether[(
@defproc[(=? [n number?] ...+) boolean?]
@defproc[(<? [n real?] ...+) boolean?]
@defproc[(>? [n real?] ...+) boolean?]
@defproc[(<=? [n real?] ...+) boolean?]
@defproc[(>=? [n real?] ...+) boolean?]
)]{
Same as @scheme[=], @scheme[<], etc.}
@deftogether[(
@defproc[(1+ [n number?]) number?]
@defproc[(1- [n number?]) number?]
)]{
Same as @scheme[add1] and @scheme[sub1].}
@defproc[(gentmp [base (or/c string? symbol?) "g"]) symbol?]{
Same as @scheme[gensym].}
@defproc[(flush-output-port [o output-port? (current-output-port)]) void?]{
Same as @scheme[flush-output].}
@defproc[(real-time) exact-integer?]{
Same as @scheme[current-milliseconds].}
@defproc[(atom? [v any/c]) any]{
Same as @scheme[(not (pair? v))] (which does not actually imply an
atomic value).}
@defform*[[(define-structure (name-id field-id ...))
(define-structure (name-id field-id ...)
((init-field-id init-expr) ...))]]{
Like @scheme[define-struct], except that the @scheme[name-id] is moved
inside the parenthesis for fields. In addition,
@scheme[init-field-id]s can be specified with automatic initial-value
expression.
The @scheme[init-field-id]s do not have corresponding arguments for
the @schemeidfont{make-}@scheme[name-id] constructor. Instead, each
@scheme[init-field-id]'s @scheme[init-expr] is evaluated to obtain the
field's value when the constructor is called. The @scheme[field-id]s
are bound in @scheme[init-expr]s, but not other
@scheme[init-field-id]s.
@examples[
#:eval compat-eval
(define-structure (add left right) ([sum (+ left right)]))
(add-sum (make-add 3 6))
]}
@deftogether[(
@defproc[(getprop [sym symbol?][property symbol?][default any/c #f]) any/c]
@defproc[(putprop [sym symbol?][property symbol?][value any/c]) void?]
)]{
The @scheme[getprop] function gets a property value associated with
@scheme[sym]. The @scheme[property] argument names the property to be
found. If the property is not found, @scheme[default] is returned.
The properties obtained with @scheme[getprop] are the ones installed
with @scheme[putprop].}
@defproc[(new-cafe [eval-handler (any/c . -> . any) #f]) any]{
Emulates Chez Scheme's @scheme[new-cafe] by installing
@scheme[eval-handler] into the @scheme[current-eval] parameter while
running @scheme[read-eval-print]. In addition, @scheme[current-exit]
is set to escape from the call to @scheme[new-cafe].}

View File

@ -0,0 +1,34 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/compile
compiler/compiler
compiler/cm))
@mzlib[#:mode title compile]
@defproc[(compile-file [src path-string?]
[dest path-string? (let-values ([(base name dir?) (split-path src)])
(build-path base "compiled"
(path-add-suffix name #".zo")))]
[filter (any/c . -> . any/c) values])
path?]{
Compiles the Scheme file @scheme[src] and saves the compiled code to
@scheme[dest]. If @scheme[dest] is not provided and the
@filepath{compiled} subdirectory does not already exist, the
subdirectory is created. The result of @scheme[compile-file] is the
destination file's path.
If the @scheme[filter] procedure is provided, it is applied to each
source expression, and the result is compiled.
The @scheme[compile-file] procedure is designed for compiling modules
files, in that each expression in @scheme[src] is compiled
independently. If @scheme[src] does not contain a single
@scheme[module] expression, then earlier expressions can affect the
compilation of later expressions when @scheme[src] is loaded
directly. An appropriate @scheme[filter] can make compilation behave
like evaluation, but the problem is also solved (as much as possible)
by the @scheme[compile-zos] procedure.
See also @scheme[managed-compile-zo].}

View File

@ -0,0 +1,8 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/contract))
@mzlib[#:mode title contract]
Re-provides much of @schememodname[scheme/contract], except....

View File

@ -0,0 +1,67 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/defmacro
(only-in scheme/base syntax->datum datum->syntax)))
@(define ref '(lib "scribblings/reference/reference.scrbl"))
@mzlib[#:mode title defmacro]
@deftogether[(
@defform*[[(define-macro id expr)
(define-macro (id . formals) body ...+)]]
@defform/subs[(defmacro id formals body ...+)
([formals (id ...)
id
(id ...+ . id)])]
)]{
Defines a (non-hygienic) macro @scheme[id] through a procedure that
manipulates S-expressions, as opposed to @techlink[#:doc ref]{syntax
objects}.
In the first form, @scheme[expr] must produce a procedure. In the
second form, @scheme[formals] determines the formal arguments of the
procedure, as in @scheme[lambda], and the @scheme[expr]s are the
procedure body. The last form, with @scheme[defmacro], is like the
second form, but with slightly different parentheses.
In all cases, the procedure is generated in the @techlink[#:doc
ref]{transformer environment}, not the normal environment.
In a use of the macro,
@schemeblock[
(id datum ...)
]
@scheme[syntax->datum] is applied to the expression, and the
transformer procedure is applied to the @scheme[cdr] of the resulting
list. If the number of @scheme[datum]s does not match the procedure's
arity, or if @scheme[id] is used in a context that does not match the
above pattern, then a syntax error is reported.
After the macro procedure returns, the result is compared to the
procedure's arguments. For each value that appears exactly once within
the arguments (or, more precisely, within the S-expression derived
from the original source syntax), if the same value appears in the
result, it is replaced with a syntax object from the original
expression. This heuristic substitution preserves source location
information in many cases, despite the macro procedure's operation on
raw S-expressions.
After substituting syntax objects for preserved values, the entire
macro result is converted to syntax with @scheme[datum->syntax]. The
original expression supplies the lexical context and source location
for converted elements.
@bold{Important:} Although @scheme[define-macro] is non-hygienic, it
is still restricted by PLT Scheme's phase separation rules. This
means that a macro cannot access run-time bindings, because it is
executed in the syntax-expansion phase. Translating code that
involves @scheme[define-macro] or @scheme[defmacro] from an
implementation without this restriction usually implies separating
macro related functionality into a @scheme[begin-for-syntax] or a
module (that will be imported with @scheme[require-for-syntax]) and
properly distinguishing syntactic information from run-time
information.}

View File

@ -0,0 +1,272 @@
#lang scribble/doc
@(require "common.ss"
scribble/eval
(for-label mzlib/etc
scheme/bool
scheme/local
setup/dirs
(only-in scheme build-list build-string build-vector
symbol=?)))
@(define etc-eval (make-base-eval))
@interaction-eval[#:eval etc-eval (require mzlib/etc)]
@(begin
(define-syntax-rule (bind id)
(begin
(require scheme/base)
(define id (scheme lambda))))
(bind base-lambda))
@mzlib[#:mode title etc]
The @schememodname[mzlib/etc] library re-exports the following
@schememodname[scheme/base] and other libraries:
@schemeblock[
boolean=?
true
false
build-list
build-string
build-vector
compose
local
symbol=?
]
@defform[(begin-lifted expr ...+)]
Lifts the @scheme[expr]s so that they are evaluated once at the ``top
level'' of the current context, and the result of the last
@scheme[expr] is used for every evaluation of the
@scheme[begin-lifted] form.
When this form is used as a run-time expression within a module, the
``top level'' corresponds to the module's top level, so that each
@scheme[expr] is evaluated once for each invocation of the
module. When it is used as a run-time expression outside of a module,
the ``top level'' corresponds to the true top level. When this form is
used in a @scheme[define-syntax], @scheme[letrec-syntax],
etc. binding, the ``top level'' corresponds to the beginning of the
binding's right-hand side. Other forms may redefine ``top level''
(using @scheme[local-expand/capture-lifts]) for the expressions that
they enclose.
@defform[(begin-with-definitions defn-or-expr ...)]{
Supports a mixture of expressions and mutually recursive definitions,
much like a @scheme[module] body. Unlike in a @scheme[module],
however, syntax definitions cannot be used to generate other immediate
definitions (though they can be used for expressions).
The result of the @scheme[begin-with-definitions] form is the result
of the last @scheme[defn-or-expr] if it is an expression,
@|void-const| otherwise. If no @scheme[defn-or-expr] is provided
(after flattening @scheme[begin] forms), the result is @|void-const|.}
@defform[(define-syntax-set (id ...) defn ...)]{
Similar to @scheme[define-syntaxes], but instead of a single body
expression, a sequence of definitions follows the sequence of defined
identifiers. For each @scheme[identifier], the @scheme[defn]s should
include a definition for @scheme[id]@schemeidfont{/proc}. The value
for @scheme[id]@schemeidfont{/proc} is used as the (expansion-time)
value for @scheme[id].
The @scheme[define-syntax-set] form is useful for defining a set of
syntax transformers that share helper functions, though
@scheme[begin-for-syntax] now serves essentially the same purposes.
@as-examples[
@schemeblock[
(define-syntax-set (let-current-continuation
let-current-escape-continuation)
(define (mk call-id)
(lambda (stx)
(syntax-case stx ()
[(_ id body1 body ...)
(with-syntax ([call call-id])
(syntax (call (lambda (id) body1 body ...))))])))
(define let-current-continuation/proc
(mk (quote-syntax call/cc)))
(define let-current-escape-continuation/proc
(mk (quote-syntax call/ec))))
]]}
@defform*[#:literals (else)
[(evcase key-expr (value-expr body-expr ...) ...+)
(evcase key-expr (value-expr body-expr ...) ... [else body-expr ...])]]{
The @scheme[evcase] form is similar to @scheme[case], except that
expressions are provided in each clause instead of a sequence of
data. After @scheme[key-expr] is evaluated, each @scheme[value-expr]
is evaluated until a value is found that is @scheme[eqv?] to the key
value; when a matching value is found, the corresponding
@scheme[body-expr]s are evaluated and the value(s) for the last is the
result of the entire @scheme[evcase] expression.}
@defproc[(identity [v any/c]) any/c]{
Returns @scheme[v].}
@defform/subs[#:literals (val rec vals recs _ values)
(let+ clause body-expr ...+)
([clause (val target expr)
(rec target expr)
(vals (target ...) expr)
(recs (target expr) ...)
(_ expr ...)]
[target id
(values id ...)])]{
A binding construct that specifies scoping on a per-binding basis
instead of a per-expression basis. It helps eliminate rightward-drift
in programs. It looks similar to @scheme[let], except each clause has
an additional keyword tag before the binding variables.
Each @scheme[clause] has one of the following forms:
@itemize{
@item{@scheme[(val target expr)] : Binds @scheme[target]
non-recursively to @scheme[expr].}
@item{@scheme[(rec target expr)] : Binds @scheme[target] recursively to
@scheme[expr].}
@item{@scheme[(vals (target expr) ...)] : The @scheme[target]s are
bound to the @scheme[expr]s. The environment of the @scheme[expr]s is
the environment active before this clause.}
@item{@scheme[(recs (target expr) ...)] : The @scheme[targets]s are
bound to the @scheme[expr]s. The environment of the @scheme[expr]s
includes all of the @scheme[targets]s.}
@item{@scheme[(_ expr ...)] : Evaluates the @scheme[expr]s without
binding any variables.}
}
The clauses bind left-to-right. When a @scheme[target] is
@scheme[(values id ...)], multiple values returned by the
corresponding expression are bound to the multiple variables.
@examples[
#:eval etc-eval
(let+ ([val (values x y) (values 1 2)])
(list x y))
(let ([x 1])
(let+ ([val x 3]
[val y x])
y))
]}
@defproc[(loop-until [start any/c][done? (any/c . -> . any)]
[next (any/c . -> . any/c)]
[f (any/c . -> . any)])
void?]{
Repeatedly invokes the @scheme[f] procedure until the @scheme[done?]
procedure returns @scheme[#t]:
@schemeblock[
(define loop-until
(lambda (start done? next f)
(let loop ([i start])
(unless (done? i)
(f i)
(loop (next i))))))
]}
@defproc[(namespace-defined? [sym symbol?]) boolean?]{
Returns @scheme[#t] if @scheme[namespace-variable-value] would return
a value for @scheme[sym], @scheme[#f] otherwise.}
@defform[(nand expr ...)]{
Same as @scheme[(not (and expr ...))].}
@defform[(nor expr ...)]{
Same as @scheme[(not (or expr ...))].}
@defform[(opt-lambda formals body ...+)]{
Supports optional (but not keyword) arguments like @base-lambda from
@scheme[scheme/base].}
@defform[(recur id bindings body ...+)]{
Equivalent to @scheme[(let id bindings body ...+)].}
@defform*[[(rec id value-expr)
(rec (id arg-id ...) expr)
(rec (id arg-id ... . rest-id) expr)]]{
Equivalent, respectively, to
@schemeblock[
(letrec ((id value-expr)) id)
(letrec ((id (lambda (arg-id ...) value-expr))) id)
(letrec ((id (lambda (arg-id ... . rest-id) value-expr))) id)
]}
@deftogether[(
@defform[(this-expression-source-directory)]
@defform[(this-expression-file-name)]
)]{
@margin-note{See @schememodname[scheme/runtime-path] for a definition form
that works better when creating executables.}
Expands to an expression that evaluates to the name of the directory
of the file containing the source expression, or the name of the file
containing the source expression.
If the expression has a source module, then the expansion attempts to
determine the module's run-time location. This location is determined
by preserving the original expression as a syntax object, extracting
its source module path at run time, and then resolving the module
path.
Otherwise, the source expression's file is determined through source
location information associated with the syntax, if it is present. If
the expression has no source, or if no directory can be determined at
run time, the expansion falls back to using source-location
information associated with the expression.
As a last resort, @scheme[#f] is used for the file name; for the
directory name, @scheme[current-load-relative-directory] is used if it
is not @scheme[#f], and @scheme[current-directory] is used if all else
fails.
A directory path is stored in bytes in the expanded code, unless the
file is within the result of @scheme[find-collects-dir], in which case
the expansion records the path relative to
@scheme[(find-collects-dir)] and then reconstructs it using
@scheme[(find-collects-dir)] at run time.}
@defform[#:literals (quote unsyntax scheme)
(hash-table (#,(scheme quote) flag) ... (key-expr val-expr) ...)]{
Creates a new hash-table providing the quoted flags (if any) to
@scheme[make-hash-table], and them mapping each key to the
corresponding values.}

View File

@ -0,0 +1,64 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/file
scheme/contract))
@mzlib[#:mode title file]
The @schememodname[mzlib/file] library mostly re-exports from
@schememodname[scheme/file]:
@schemeblock[
find-relative-path
explode-path
normalize-path
filename-extension
file-name-from-path
path-only
delete-directory/files
copy-directory/files
make-directory*
make-temporary-file
get-preference
put-preferences
fold-files
find-files
pathlist-closure
]
@deftogether[(
@defproc[(call-with-input-file* [file path-string?]
[proc (input-port? -> any)]
[mode (one-of/c 'text 'binary) 'binary])
any]
@defproc[(call-with-output-file* [file path-string?]
[proc (output-port? -> any)]
[mode (one-of/c 'text 'binary) 'binary]
[exists (one-of/c 'error 'append 'update
'replace 'truncate 'truncate/replace) 'error])
any]
)]{
Like @scheme[call-with-input-file]and @scheme[call-with-output-file],
except that the opened port is closed if control escapes from the body
of @scheme[proc].}
@deftogether[(
@defproc[(build-relative-path [base (or/c path-string?
(one-of/c 'up 'same))]
[sub (or/c (and/c path-string?
relative-path?)
(one-of/c 'up 'same))] ...)
(and/c path? relative-path?)]
@defproc[(build-absolute-path [base (or/c (and/c path-string?
(not/c relative-path?))
(one-of/c 'up 'same))]
[sub (or/c (and/c path-string?
(not/c complete-path?))
(one-of/c 'up 'same))] ...)
(and/c path? absolute-path?)]
)]{
Like @scheme[build-path], but with extra constraints to ensure a
relative or absolute result.}

View File

@ -0,0 +1,45 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/for))
@mzlib[#:mode title for]
The @schememodname[mzlib/for] library re-exports from
@schememodname[scheme/base]:
@schemeblock[
for/fold for*/fold
for for*
for/list for*/list
for/lists for*/lists
for/and for*/and
for/or for*/or
for/first for*/first
for/last for*/last
for/fold/derived for*/fold/derived
in-range
in-naturals
in-list
in-vector
in-string
in-bytes
in-input-port-bytes
in-input-port-chars
in-hash-table
in-hash-table-keys
in-hash-table-values
in-hash-table-pairs
in-parallel
stop-before
stop-after
in-indexed
sequence?
sequence-generate
define-sequence-syntax
make-do-sequence
:do-in]

View File

@ -0,0 +1,68 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/include))
@mzlib[#:mode title include]
Similar to @schememodname[scheme/include], but with a different syntax
for paths.
@defform/subs[#:literals (build-path lib up same)
(include path-spec)
([path-spec string
(build-path elem ...+)
(lib file-string collection-string ...)]
[elem string
up
same])]{
Inlines the syntax in the designated file in place of the
@scheme[include] expression. The @scheme[path-spec] can be any of the
following:
@itemize{
@item{A literal string that specifies a path to include, parsed
according to the platform's conventions (which means that it is
not portable).}
@item{A path construction of the form @scheme[(build-path elem
...+)], where @scheme[build-path] is
@scheme[module-identifier=?] either to the @scheme[build-path]
export from @scheme[mzscheme] or to the top-level
@scheme[build-path], and where each @scheme[elem] is a path
string, @scheme[up] (unquoted), or @scheme[same] (unquoted).
The @scheme[elem]s are combined in the same way as for the
@scheme[build-path] function to obtain the path to include.}
@item{A path construction of the form @scheme[(lib file-string
collection-string ...)], where @scheme[lib] is free or refers
to a top-level @scheme[lib] variable. The
@scheme[collection-string]s are passed to
@scheme[collection-path] to obtain a directory; if no
@scheme[collection-strings]s are supplied, @scheme["mzlib"] is
used. The @scheme[file-string] is then appended to the
directory using @scheme[build-path] to obtain the path to
include.}
}
If @scheme[path-spec] specifies a relative path to include, the path
is resolved relative to the source for the @scheme[include]
expression, if that source is a complete path string. If the source is
not a complete path string, then @scheme[path-spec] is resolved
relative to the current load relative directory if one is available,
or to the current directory otherwise.
The included syntax is given the lexical context of the
@scheme[include] expression.}
@deftogether[(
@defform[(include-at/relative-to context source path-spec)]
@defform[(include-at/relative-to/reader context source path-spec reader-expr)]
@defform[(include/reader path-spec reader-expr)]
)]{
Variants of @scheme[include] analogous to the variants of
@schememodname[scheme/include].}

View File

@ -0,0 +1,5 @@
#lang setup/infotab
(define name "MzLib documentation")
(define scribblings '(("mzlib.scrbl" (multi-page))))
(define doc-categories '(legacy))

View File

@ -0,0 +1,145 @@
#lang scribble/doc
@(require "common.ss"
(for-label mzlib/integer-set))
@mzlib[#:mode title integer-set]
The @schememodname[mzlib/integer-set] library provides functions for
working with finite sets of integers. This module is designed for
sets that are compactly represented as groups of intervals, even when
their cardinality is large. For example, the set of integers from
@math{-1000000} to @math{1000000} except for @math{0}, can be represented as
@math{{[-1000000, -1], [1, 1000000]}}. This data structure would not be
a good choice for the set of all odd integers between @math{0} and
@math{1000000}, which would be @math{{[1, 1], [3, 3], ... [999999,
999999]}}.
In addition to the @defterm{integer set} abstract type, a
@defterm{well-formed set} is a list of pairs of exact integers, where
each pair represents a closed range of integers, and the entire set is
the union of the ranges. The ranges must be disjoint and increasing.
Further, adjacent ranges must have at least one integer between them.
For example: @scheme['((-1 . 2) (4 . 10))] is a well-formed-set as is
@scheme['((1 . 1) (3 . 3))], but @scheme['((1 . 5) (6 . 7))],
@scheme['((1 . 5) (-3 . -1))], @scheme['((5 . 1))], and @scheme['((1
. 5) (3 . 6))] are not.
@defproc[(make-integer-set [wfs well-formed-set?]) integer-set?]{
Creates an integer set from a well-formed set.}
@defproc[(integer-set-contents [s integer-set?]) well-formed-set?]{
Produces a well-formed set from an integer set.}
@defproc[(set-integer-set-contents! [s integer-set?][wfs well-formed-set?]) void?]{
Mutates an integer set.}
@defproc[(integer-set? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is an integer set, @scheme[#f]
otherwise.}
@defproc[(well-formed-set? [v any/c]) boolean?]{
Returns @scheme[#t] if @scheme[v] is a well-formed set, @scheme[#f]
otherwise.}
@defproc*[([(make-range) integer-set?]
[(make-range [elem exact-integer?]) integer-set?]
[(make-range [start exact-integer?]
[end exact-integer?]) integer-set?])]{
Produces, respectively, an empty integer set, an integer set
containing only @scheme[elem], or an integer set containing the
integers from @scheme[start] to @scheme[end] inclusive, where
@scheme[(start . <= . end)].}
@defproc[(intersect [x integer-set?][y integer-set?]) integer-set?]{
Returns the intersection of the given sets.}
@defproc[(difference [x integer-set?][y integer-set?]) integer-set?]{
Returns the difference of the given sets (i.e., elements in @scheme[x]
that are not in @scheme[y]).}
@defproc[(union [x integer-set?][y integer-set?]) integer-set?]{
Returns the union of the given sets.}
@defproc[(split [x integer-set?][y integer-set?]) integer-set?]{
Produces three values: the first is the intersection of @scheme[x] and
@scheme[y], the second is the difference @scheme[x] remove @scheme[y],
and the third is the difference @scheme[y] remove @scheme[x].}
@defproc[(complement [s integer-set?]
[start exact-integer?]
[end exact-integer?]) any]
Returns the a set containing the elements between @scheme[start] to
@scheme[end] inclusive that are not in @scheme[s], where
@scheme[(start-k . <= . end-k)].}
@defproc[(xor [x integer-set?][y integer-set?]) integer-set?]{
Returns an integer set containing every member of @scheme[x]
and @scheme[y] that is not in both sets.}
@defproc[(member? [k exact-integer?][s integer-set?]) boolean?]{
Returns @scheme[#t] if @scheme[k] is in @scheme[s], @scheme[#f]
otherwise.}
@defproc[(get-integer [integer-set any/c]) (or/c exact-integer? false/c)]{
Returns a member of @scheme[integer-set], or @scheme[#f] if
@scheme[integer-set] is empty.}
@defproc[(foldr [proc (exact-integer? any/c . -> . any/c)]
[base-v any/c]
[s integer-set?])
any/c]{
Applies @scheme[proc] to each member of @scheme[s] in ascending order,
where the first argument to @scheme[proc] is the set member, and the
second argument is the fold result starting with @scheme[base-v]. For
example, @scheme[(foldr cons null s)] returns a list of all the
integers in @scheme[s], sorted in increasing order.}
@defproc[(partition [s integer-set-list?]) (listof integer-set?)]{
Returns the coarsest refinement of the sets in @scheme[s] such that
the sets in the result list are pairwise disjoint. For example,
partitioning the sets that represent @scheme['((1 . 2) (5 . 10))] and
@scheme['((2 . 2) (6 . 6) (12 . 12))] produces the a list containing
the sets for @scheme['((1 . 1) (5 . 5) (7 . 10))] @scheme['((2 . 2) (6
. 6))], and @scheme['((12 . 12))].}
@defproc[(card [s integer-set?]) exact-nonnegative-integer?]{
Returns the number of integers in the given integer set.}
@defproc[(subset? [x integer-set?][y integer-set?]) boolean?]{
Returns true if every integer in @scheme[x] is also in
@scheme[y], otherwise @scheme[#f].}

View File

@ -0,0 +1,447 @@
#lang scribble/doc
@(require "common.ss"
scribble/eval
(for-label mzlib/kw
mzlib/etc))
@(define kw-eval (make-base-eval))
@interaction-eval[#:eval kw-eval (require mzscheme)]
@interaction-eval[#:eval kw-eval (require mzlib/kw)]
@(begin
(define-syntax-rule (bind id)
(begin
(require scheme/base)
(define id (scheme lambda))))
(bind base-lambda))
@mzlib[#:mode title kw]
@margin-note{The @base-lambda and procedure-application forms of
@scheme[scheme/base] support keyword arguments, and it is
@emph{not} compatible with the @scheme[mzlib/kw]
library.}
@deftogether[(
@defform[(lambda/kw kw-formals body ...+)]
@defform/subs[
(define/kw (head args) body ...+)
([kw-formals id
(id ... [#:optional optional-spec ...]
[#:key key-spec ...]
[rest/mode-spec ...])
(id ... . id)]
[optional-spec id
(id default-expr)]
[key-spec id
(id default-expr)
(id keyword default-expr)]
[rest/mode-spec (code:line #:rest id)
(code:line #:other-keys id)
(code:line #:other-keys+body id)
(code:line #:all-keys id)
(code:line #:body kw-formals)
(code:line #:allow-other-keys)
(code:line #:forbid-other-keys)
(code:line #:allow-duplicate-keys)
(code:line #:forbid-duplicate-keys)
(code:line #:allow-body)
(code:line #:forbid-body)
(code:line #:allow-anything)
(code:line #:forbid-anything)]
[head id
(head . kw-formals)])
])]{
Like @scheme[lambda], but with optional and keyword-based argument
processing. This form is similar to an extended version of Common
Lisp procedure arguments (but note the differences below). When used
with plain variable names, @scheme[lambda/kw] expands to a plain
@scheme[lambda], so @scheme[lambda/kw] is suitable for a language
module that will use it to replace @scheme[lambda]. Also, when used
with only optionals, the resulting procedure is similar to
@scheme[opt-lambda] (but a bit faster).
In addition to @scheme[lambda/kw], @scheme[define/kw] is similar to
@scheme[define], except that the @scheme[formals] are as in
@scheme[lambda/kw]. Like @scheme[define], this form can be used with
nested parenthesis for curried functions (the MIT-style generalization
of @scheme[define]).
The syntax of @scheme[lambda/kw] is the same as @scheme[lambda],
except for the list of formal argument specifications. These
specifications can hold (zero or more) plain argument names, then an
optionals (and defaults) section that begins after an
@scheme[#:optional] marker, then a keyword section that is marked by
@scheme[#:keyword], and finally a section holding rest and
``rest''-like arguments which are described below, together with
argument processing flag directives. Each section is optional, but
the order of the sections must be as listed. Of course, all binding
@scheme[id]s must be unique.
The following sections describe each part of the @scheme[kw-formals].}
@; ----------------------------------------
@section{Required Arguments}
Required arguments correspond to @scheme[id]s that appear before any
keyword marker in the argument list. They determine the minimum arity
of the resulting procedure.
@; ----------------------------------------
@section{Optional Arguments}
The optional-arguments section follows an
@as-index{@scheme[#:optional]} marker in the @scheme[_kw-formals].
Each optional argument can take the form of a parenthesized variable
and a default expression; the latter is used if a value is not given
at the call site. The default expression can be omitted (along with
the parentheses), in which case @scheme[#f] is the default.
The default expression's environment includes all previous arguments,
both required and optional names. With @math{k} optionals after
@math{n} required arguments, and with no keyword arguments or
rest-like arguments, the resulting procedure accept between @math{n}
and @math{n+k} arguments, inclusive.
The treatment of optionals is efficient, with an important caveat:
default expressions appear multiple times in the resulting
@scheme[case-lambda]. For example, the default expression for the last
optional argument appears @math{k-1} times (but no expression is ever
evaluated more than once in a procedure call). This expansion risks
exponential blow-up is if @scheme[lambda/kw] is used in a default
expression of a @scheme[lambda/kw], etc. The bottom line, however, is
that @scheme[lambda/kw] is a sensible choice, due to its enhanced
efficiency, even when you need only optional arguments.
Using both optional and keyword arguments is possible, but note that
the resulting behavior differs from traditional keyword facilities
(including the one in Common Lisp). See the following section for
details.
@; ----------------------------------------
@section{Keyword Arguments}
A keyword argument section is marked by a @as-index{@scheme[#:key]}.
If it is used with optional arguments, then the keyword specifications
must follow the optional arguments (which mirrors the use in call
sites; where optionals are given before keywords).
When a procedure accepts both optional and keyword arguments, the
argument-handling convention is slightly different than in traditional
keyword-argument facilities: a keyword after required arguments marks
the beginning of keyword arguments, no matter how many optional
arguments have been provided before the keyword. This convention
restricts the procedure's non-keyword optional arguments to
non-keyword values, but it also avoids confusion when mixing optional
arguments and keywords. For example, when a procedure that takes two
optional arguments and a keyword argument @scheme[#:x] is called with
@scheme[#:x 1], then the optional arguments get their default values
and the keyword argument is bound to @scheme[1]. (The traditional
behavior would bind @scheme[#:x] and @scheme[1] to the two optional
arguments.) When the same procedure is called with @scheme[1 #:x 2],
the first optional argument is bound to @scheme[1], the second
optional argument is bound to its default, and the keyword argument is
bound to @scheme[2]. (The traditional behavior would report an error,
because @scheme[2] is provided where @scheme[#:x] is expected.)
Like optional arguments, each keyword argument is specified as a
parenthesized variable name and a default expression. The default
expression can be omitted (with the parentheses), in which case
@scheme[#f] is the default value. The keyword used at a call site for
the corresponding variable has the same name as the variable; a third
form of keyword arguments has three parts---a variable name, a
keyword, and a default expression---to allow the name of the locally
bound variable to differ from the keyword used at call sites.
When calling a procedure with keyword arguments, the required argument
(and all optional arguments, if specified) must be followed by an even
number of arguments, where the first argument is a keyword that
determines which variable should get the following value, etc. If the
same keyword appears multiple times (and if multiple instances of the
keyword are allowed; see @secref["mode-keywords"]), the value after
the first occurrence is used for the variable:
@examples[
#:eval kw-eval
((lambda/kw (#:key x [y 2] [z #:zz 3] #:allow-duplicate-keys)
(list x y z))
#:x 'x #:zz 'z #:x "foo")
]
Default expressions are evaluated only for keyword arguments that do
not receive a value for a particular call. Like optional arguments,
each default expression is evaluated in an environment that includes
all previous bindings (required, optional, and keywords that were
specified on its left).
See @secref["mode-keywords"] for information on when duplicate or
unknown keywords are allowed at a call site.
@; ----------------------------------------
@section{Rest and Rest-like Arguments}
The last @scheme[_kw-formals] section---after the required, optional,
and keyword arguments---may contain specifications for rest-like
arguments and/or mode keywords. Up to five rest-like arguments can be
declared, each with an @scheme[_id] to bind:
@itemize{
@item{@as-index{@scheme[#:rest]} --- The variable is bound to the
list of ``rest'' arguments, which is the list of all values after
the required and the optional values. This list includes all
keyword-value pairs, exactly as they are specified at the call site.
Scheme's usual dot-notation is accepted in @scheme[_kw-formals] only
if no other meta-keywords are specified, since it is not clear
whether it should specify the same binding as a @scheme[#:rest] or
as a @scheme[#:body]. The dot notation is allowed without
meta-keywords to make the @scheme[lambda/kw] syntax compatible with
@scheme[lambda].}
@item{@as-index{@scheme[#:body]} --- The variable is bound to all
arguments after keyword--value pairs. (This is different from
Common Lisp's @scheme[&body], which is a synonym for
@scheme[&rest].) More generally, a @scheme[#:body] specification
can be followed by another @scheme[_kw-formals], not just a single
@scheme[_id]; see @secref["kw-body"] for more information.}
@item{@as-index{@scheme[#:all-keys]} --- the variable is bound to the
list of all keyword-values from the call site, which is always a
proper prefix of a @scheme[#:rest] argument. (If no @scheme[#:body]
arguments are declared, then @scheme[#:all-keys] binds the same as
@scheme[#:rest].) See also @scheme[keyword-get].}
@item{@scheme[#:other-keys] --- The variable is bound like an
@scheme[#:all-keys] variable, except that all keywords specified in
the @scheme[kw-formals] are removed from the list. When a keyword
is used multiple times at a call cite (and this is allowed), only
the first instances is removed for the @scheme[#:other-keys]
binding.}
@item{@scheme[#:other-keys+body] --- the variable is bound like a
@scheme[#:rest] variable, except that all keywords specified in the
@scheme[_kw-formals] are removed from the list. When a keyword is
used multiple times at a call site (and this is allowed), only the
first instance us removed for the @scheme[#:other-keys+body]
binding. (When no @scheme[#:body] variables are specified, then
@scheme[#:other-keys+body] is the same as @scheme[#:other-keys].)}
}
In the following example, all rest-like arguments are used and have different
bindings:
@examples[
#:eval kw-eval
((lambda/kw (#:key x y
#:rest r
#:other-keys+body rk
#:all-keys ak
#:other-keys ok
#:body b)
(list r rk b ak ok))
#:z 1 #:x 2 2 3 4)
]
Note that the following invariants always hold:
@itemize{
@item{@scheme[_rest] = @scheme[(append _all-keys _body)]}
@item{@scheme[_other-keys+body] = @scheme[(append _other-keys _body)]}
}
To write a procedure that uses a few keyword argument values, and that
also calls another procedure with the same list of arguments
(including all keywords), use @scheme[#:other-keys] (or
@scheme[#:other-keys+body]). The Common Lisp approach is to specify
@scheme[:allow-other-keys], so that the second procedure call will not
cause an error due to unknown keywords, but the
@scheme[:allow-other-keys] approach risks confusing the two layers of
keywords.
@; ----------------------------------------
@section[#:tag "kw-body"]{Body Argument}
The most notable divergence from Common Lisp in @scheme[lambda/kw] is
the @scheme[#:body] argument, and the fact that it is possible at a
call site to pass plain values after the keyword-value pairs. The
@scheme[#:body] binding is useful for procedure calls that use
keyword-value pairs as sort of an attribute list before the actual
arguments to the procedure. For example, consider a procedure that
accepts any number of numeric arguments and will apply a procedure to
them, but the procedure can be specified as an optional keyword
argument. It is easily implemented with a @scheme[#:body] argument:
@examples[
#:eval kw-eval
(define/kw (mathop #:key [op +] #:body b)
(apply op b))
(mathop 1 2 3)
(mathop #:op max 1 2 3)
]
(Note that the first body value cannot itself be a keyword.)
A @scheme[#:body] declaration works as an arbitrary
@scheme[kw-formals], not just a single variable like @scheme[b] in the
above example. For example, to make the above @scheme[mathop] work
only on three arguments that follow the keyword, use @scheme[(x y z)]
instead of @scheme[b]:
@examples[
#:eval kw-eval
(define/kw (mathop #:key [op +] #:body (x y z))
(op x y z))
]
In general, @scheme[#:body] handling is compiled to a sub procedure
using @scheme[lambda/kw], so that a procedure can use more then one
level of keyword arguments. For example:
@examples[
#:eval kw-eval
(define/kw (mathop #:key [op +]
#:body (x y z #:key [convert values]))
(op (convert x) (convert y) (convert z)))
(mathop #:op * 2 4 6 #:convert exact->inexact)
]
Obviously, nested keyword arguments works only when non-keyword
arguments separate the sets.
Run-time errors during such calls report a mismatch for a procedure
with a name that is based on the original name plus a @schemeidfont{~body}
suffix:
@examples[
#:eval kw-eval
(mathop #:op * 2 4)
]
@; ----------------------------------------
@section[#:tag "mode-keywords"]{Mode Keywords}
Finally, the argument list of a @scheme[lambda/kw] can contain
keywords that serve as mode flags to control error reporting.
@itemize{
@item{@as-index{@scheme[#:allow-other-keys]} --- The keyword-value
sequence at the call site @italic{can} include keywords that are not
listed in the keyword part of the @scheme[lambda/kw] form.}
@item{@as-index{@scheme[#:forbid-other-keys]} --- The keyword-value
sequence at the call site @italic{cannot} include keywords that are
not listed in the keyword part of the @scheme[lambda/kw] form,
otherwise the @scheme[exn:fail:contract] exception is raised.}
@item{@as-index{@scheme[#:allow-duplicate-keys]} --- The
keyword-value list at the call site @emph{can} include duplicate
values associated with same keyword, the first one is used.}
@item{@as-index{@scheme[#:forbid-duplicate-keys]} --- The
keyword-value list at the call site @italic{cannot} include
duplicate values for keywords, otherwise the
@scheme[exn:fail:contract] exception is raised. This restriction
applies only to keywords that are listed in the keyword part of the
@scheme[lambda/kw] form --- if other keys are allowed, this
restriction does not apply to them.}
@item{@as-index{@scheme[#:allow-body]} --- Body arguments
@italic{can} be specified at the call site after all keyword-value
pairs.}
@item{@as-index{@scheme[#:forbid-body]} --- Body arguments
@italic{cannot} be specified at the call site after all
keyword-value pairs.}
@item{@as-index{@scheme[#:allow-anything]} --- Allows all of the
above, and treat a single keyword at the end of an argument list as
a @scheme[#:body], a situation that is usually an error. When this
is used and no rest-like arguments are used except @scheme[#:rest],
an extra loop is saved and calling the procedures is faster (around
20%).}
@item{@as-index{@scheme[#:forbid-anything]} --- Forbids all of the
above, ensuring that calls are as restricted as possible.}
}
These above mode markers are rarely needed, because the default modes
are determined by the declared rest-like arguments:
@itemize{
@item{The default is to allow other keys if a @scheme[#:rest],
@scheme[#:other-keys+body], @scheme[#:all-keys], or
@scheme[#:other-keys] variable is declared (and an
@scheme[#:other-keys] declaration requires allowing other keys).}
@item{The default is to allow duplicate keys if a @scheme[#:rest] or
@scheme[#:all-keys] variable is declared.}
@item{The default is to allow body arguments if a @scheme[#:rest],
@scheme[#:body], or @scheme[#:other-keys+body] variable is declared
(and a @scheme[#:body] argument requires allowing them).}
}
Here's an alternate specification, which maps rest-like arguments to
the behavior that they imply:
@itemize{
@item{@scheme[#:rest]: Everything is allowed (a body, other keys,
and duplicate keys);}
@item{@scheme[#:other-keys+body]: Other keys and body are allowed,
but duplicates are not;}
@item{@scheme[#:all-keys]: Other keys and duplicate keys are allowed,
but a body is not;}
@item{@scheme[#:other-keys]: Other keys must be allowed (on by
default, cannot use with @scheme[#:forbid-other-keys]), and
duplicate keys and body are not allowed;}
@item{@scheme[#:body]: Body must be allowed (on by default, cannot use
with @scheme[#:forbid-body]) and other keys and duplicate keys and
body are not allowed;}
@item{Except for the previous two ``must''s, defaults can be
overridden by an explicit @scheme[#:allow-...] or a
@scheme[#:forbid-...] mode.}
}
@; ----------------------------------------
@section[#:tag "keyword-get"]{Property Lists}
@defproc[(keyword-get [args (listof (cons/c keyword? any/c))] [kw keyword?]
[not-found (-> any)])
any]{
Searches a list of keyword arguments (a ``property list'' or ``plist''
in Lisp jargon) for the given keyword, and returns the associated
value. It is the facility that is used by @scheme[lambda/kw] to
search for keyword values.
The @scheme[args] list is scanned from left to right, if the keyword
is found, then the next value is returned. If the @scheme[kw] was not
found, then the @scheme[not-found] thunk is used to produce a value by
applying it. If the @scheme[kw] was not found, and @scheme[not-found]
thunk is not given, @scheme[#f] is returned. (No exception is raised
if the @scheme[args] list is imbalanced, and the search stops at a
non-keyword value.)}

View File

@ -0,0 +1,155 @@
#lang scribble/doc
@(require "common.ss")
@title{@bold{MzLib}: Legacy PLT Libraries}
The @filepath{mzlib} collection contains wrappers and libraries for
compatibility with older versions of PLT Scheme. In many ways, the
libraries of the @filepath{mzlib} collection go with the
@schememodname[mzscheme] legacy language. Newer variants of many
libraries reside in the @filepath{scheme} collection.
@table-of-contents[]
@; ----------------------------------------------------------------------
@mzlib[a-signature]
Like @schememodname[scheme/signature] in @hash-lang[] form for
defining a single signature within a module, but based on
@schememodname[mzscheme] instead of @schememodname[scheme/base].
@; ----------------------------------------------------------------------
@mzlib[a-unit]
Like @schememodname[scheme/unit] in @hash-lang[] form for defining a
single unit within a module, but based on @schememodname[mzscheme]
instead of @schememodname[scheme/base].
@; ----------------------------------------------------------------------
@mzlib[async-channel]
Re-exports @schememodname[scheme/async-channel].
@; ----------------------------------------------------------------------
@include-section["awk.scrbl"]
@; ----------------------------------------------------------------------
@mzlib[class]
Re-exports @schememodname[scheme/class], except for the contract
constructors.
@; ----------------------------------------------------------------------
@include-section["class100.scrbl"]
@; ----------------------------------------------------------------------
@mzlib[cm]
Re-exports @schememodname[compiler/cm].
@; ----------------------------------------------------------------------
@mzlib[cm-accomplice]
Re-exports @schememodname[compiler/cm-accomplice].
@; ----------------------------------------------------------------------
@include-section["cmdline.scrbl"]
@; ----------------------------------------------------------------------
@include-section["cml.scrbl"]
@; ----------------------------------------------------------------------
@include-section["compat.scrbl"]
@; ----------------------------------------------------------------------
@include-section["compile.scrbl"]
@; ----------------------------------------------------------------------
@include-section["contract.scrbl"]
@; ----------------------------------------------------------------------
@mzlib[control]
Re-exports @schememodname[scheme/control].
@; ----------------------------------------------------------------------
@mzlib[date]
Re-exports @schememodname[scheme/date].
@; ----------------------------------------------------------------------
@mzlib[deflate]
Re-exports @schememodname[file/gzip].
@; ----------------------------------------------------------------------
@include-section["defmacro.scrbl"]
@; ----------------------------------------------------------------------
@include-section["etc.scrbl"]
@; ----------------------------------------------------------------------
@include-section["file.scrbl"]
@; ----------------------------------------------------------------------
@include-section["for.scrbl"]
@; ----------------------------------------------------------------------
@mzlib[foreign]
Re-exports @schememodname[scheme/foreign].
@; ----------------------------------------------------------------------
@include-section["include.scrbl"]
@; ----------------------------------------------------------------------
@mzlib[inflate]
Re-exports @schememodname[file/gunzip].
@; ----------------------------------------------------------------------
@include-section["integer-set.scrbl"]
@; ----------------------------------------------------------------------
@include-section["kw.scrbl"]
@; ----------------------------------------------------------------------
@(bibliography
(bib-entry #:key "Shivers06"
#:title "Scsh Reference Manual"
#:author "Olin Shivers, Brian D. Carlstrom, Martin Gasbichler, and Mike Sperber"
#:date "2006")
(bib-entry #:key "Reppy99"
#:title @italic{Concurrent Programming in ML}
#:author "John H. Reppy"
#:date "1999")
)

View File

@ -2,4 +2,6 @@
(define name "MzScheme")
(define version '(400))
(define scribblings '(("mzscheme.scrbl" (multi-page))))
(define doc-categories '(legacy))

View File

@ -3,7 +3,7 @@
(define name "R5RS")
(define scribblings '(("r5rs.scrbl" (multi-page))))
(define doc-categories '((language -1)))
(define doc-categories '((legacy 1)))
(define mzscheme-launcher-names '("PLT R5RS"))
(define mzscheme-launcher-libraries '("run.ss"))

View File

@ -1,4 +1,163 @@
#lang scheme/base
(require mzlib/async-channel)
(provide (all-from-out mzlib/async-channel))
(require scheme/contract)
;; This library implements buffered channels with
;; and optional buffer limit (so that puts block
;; if the buffer is full).
;; We make a fancy structure just so an async-channel
;; can be supplied directly to `sync'.
;; The alternative is to use `define-struct' and supply
;; a `async-channel-get-evt' procedure.
(define-values (struct:ac make-ac async-channel? ac-ref ac-set!)
(make-struct-type 'async-channel #f 5 0 #f
(list (cons prop:evt
;; This is the guard that is called when
;; we use an async-channel as an event
;; (to get).
(lambda (ac)
(async-channel-get-guard ac))))
(current-inspector) #f))
(define ac-enqueue-ch (make-struct-field-accessor ac-ref 0))
(define ac-dequeue-ch (make-struct-field-accessor ac-ref 1))
(define ac-empty-ch (make-struct-field-accessor ac-ref 2))
(define ac-full-ch (make-struct-field-accessor ac-ref 3))
(define ac-thread (make-struct-field-accessor ac-ref 4))
;; Make ----------------------------------------
(define make-async-channel
(lambda ([limit #f])
(let* ([enqueue-ch (make-channel)] ; for puts
[dequeue-ch (make-channel)] ; for gets
[empty-ch (make-channel)] ; for get polls
[full-ch (make-channel)] ; for put polls
[queue-first (mcons #f null)] ; queue head
[queue-last queue-first] ; queue tail
[size 0] ; queue size
;; Events:
[tell-empty
(channel-put-evt empty-ch (make-semaphore))] ; see poll->ch
[tell-full
(channel-put-evt full-ch (make-semaphore))] ; see poll->ch
[enqueue (handle-evt
enqueue-ch
(lambda (v)
;; We received a put; enqueue it:
(let ([p (mcons #f null)])
(set-mcar! queue-last v)
(set-mcdr! queue-last p)
(set! queue-last p)
(set! size (add1 size)))))]
[mk-dequeue
(lambda ()
(handle-evt
(channel-put-evt dequeue-ch (mcar queue-first))
(lambda (ignored)
;; A get succeeded; dequeue it:
(set! size (sub1 size))
(set! queue-first (mcdr queue-first)))))]
[manager-thread
;; This thread is the part that makes the channel asynchronous.
;; It waits for a combination of gets and puts as appropriate.
;; Note that we start it with `thread/suspend-kill', and we
;; resume the manager thread with the current thread everytime
;; we want to talk to the manager thread, which effectively
;; means that the manager thread is not bound by a custodian
;; that is weaker than any of its user's custodians (and thus,
;; from the user's perspective, is not bound by any custodian
;; at all).
(thread/suspend-to-kill
(lambda ()
(let loop ()
(cond
[(zero? size)
;; The queue is currently empty:
(sync enqueue tell-empty)]
[(or (not limit) (size . < . limit))
(sync enqueue (mk-dequeue))]
[else
(sync (mk-dequeue) tell-full)])
(loop))))])
(make-ac enqueue-ch dequeue-ch empty-ch full-ch manager-thread))))
;; Get ----------------------------------------
(define (async-channel-get-guard ac)
;; Make sure queue manager is running:
(thread-resume (ac-thread ac) (current-thread))
;; If it the channel is being polled, it's not
;; good enough to poll the dequeue channel, because
;; the server thread may be looping. In that case,
;; block on the dequeue channel and the empty
;; channel, and create a new waitable to report
;; the result.
(poll-guard-evt
(lambda (poll?)
(if poll?
(poll->ch (ac-dequeue-ch ac) (ac-empty-ch ac))
(ac-dequeue-ch ac)))))
(define (async-channel-get ac)
(sync ac))
(define (async-channel-try-get ac)
(sync/timeout 0 ac))
;; Put ----------------------------------------
(define (async-channel-put-evt ac v)
(letrec ([p (wrap-evt
(guard-evt
(lambda ()
;; Make sure queue manager is running:
(thread-resume (ac-thread ac) (current-thread))
(let ([p (channel-put-evt (ac-enqueue-ch ac) v)])
;; Poll handling, as in `async-channel-get-guard':
(poll-guard-evt
(lambda (poll?)
(if poll?
(poll->ch p (ac-full-ch ac))
p))))))
(lambda (ignored) p))])
p))
(define (async-channel-put ac v)
(thread-resume (ac-thread ac) (current-thread))
(sync (channel-put-evt (ac-enqueue-ch ac) v))
(void))
;; Poll helper ----------------------------------------
(define (poll->ch normal not-ready)
(sync
;; If a value becomes available,
;; create a waitable that returns
;; the value:
(wrap-evt
normal
(lambda (v)
;; Return a waitable for a successful poll:
(wrap-evt
always-evt
(lambda (ignored) v))))
;; If not-ready becomes available,
;; the result is supposed to be
;; a never-ready waitable:
not-ready))
;; Provides ----------------------------------------
(provide async-channel?)
(provide/contract (make-async-channel (case->
(-> async-channel?)
((union false/c (lambda (x)
(and (integer? x)
(exact? x)
(positive? x))))
. -> . async-channel?)))
(async-channel-get (async-channel? . -> . any/c))
(async-channel-try-get (async-channel? . -> . any/c))
(async-channel-put (async-channel? any/c . -> . any/c))
(async-channel-put-evt (async-channel? any/c . -> . evt?)))

30
collects/scheme/fasl.ss Normal file
View File

@ -0,0 +1,30 @@
#lang scheme/base
(provide s-exp->fasl
fasl->s-exp)
(define (s-exp->fasl v [out #f])
(when out
(unless (output-port? out)
(raise-type-error 'fasl->s-exp "output-port or #f" out)))
(let ([p (or out
(open-output-bytes))])
(parameterize ([current-namespace (make-base-namespace)])
(write (compile `(quote ,v)) p))
(if out
(void)
(get-output-bytes p))))
(define (fasl->s-exp b)
(unless (or (bytes? b)
(input-port? b))
(raise-type-error 'fasl->s-exp "bytes or input-port" b))
(let ([p (if (bytes? b)
(open-input-bytes b)
b)])
(let ([e (parameterize ([read-accept-compiled #t])
(read p))])
(if (compiled-expression? e)
(parameterize ([current-namespace (make-base-namespace)])
(eval e))
e))))

View File

@ -1,3 +1,2 @@
(module reader syntax/module-reader
scheme/signature/lang)

View File

@ -1856,7 +1856,7 @@
(cond
[(string? i)
(cond
[(regexp-match #rx"^(.*)([()0-9])(.*)$" i)
[(regexp-match #px"^(.*)([()0-9{}\\[\\]])(.*)$" i)
=> (lambda (m)
(append (loop (cadr m))
(list (caddr m))

View File

@ -75,7 +75,7 @@
@title[#:tag "mzlib:class" #:style 'toc]{Classes and Objects}
@note-lib[scheme/class]
@note-lib[scheme/class #:use-sources (scheme/private/class-internal)]
@local-table-of-contents[]

View File

@ -17,17 +17,22 @@
(provide AllUnix)
(provide note-lib)
(define-syntax-rule (note-lib lib . more)
(begin
(declare-exporting lib scheme)
(defmodule*/no-declare (lib)
(t "The bindings documented in this section are provided by the "
(schememodname lib)
" and "
(schememodname scheme)
" libraries, but not " (schememodname scheme/base)
"."
. more))))
(define-syntax note-lib
(syntax-rules ()
[(_ lib #:use-sources (src ...) . more)
(begin
(declare-exporting lib scheme #:use-sources (src ...))
(defmodule*/no-declare (lib)
(t "The bindings documented in this section are provided by the "
(schememodname lib)
" and "
(schememodname scheme)
" libraries, but not " (schememodname scheme/base)
"."
. more)))]
[(_ lib . more)
(note-lib lib #:use-sources () . more)]))
(provide note-lib-only)
(define-syntax-rule (note-lib-only lib . more)

View File

@ -197,21 +197,22 @@ Returns the path convention type of the current platform:
Windows.}
@defproc[(build-path [base path-string?]
[sub (or/c path-string?
@defproc[(build-path [base (or/c path-string?
(one-of/c 'up 'same))]
[sub (or/c (and/c path-string?
(not/c complete-path?))
(one-of/c 'up 'same))] ...)
path?]{
Creates a path given a base path and any number of sub-path
extensions. If @scheme[base] is an absolute path, the result is an
absolute path; if @scheme[base] is a relative path, the result is a
relative path.
absolute path, otherwise the result is a relative path.
Each @scheme[sub] must be either a relative path, the symbol
@indexed-scheme['up] (indicating the relative parent directory), or
the symbol @indexed-scheme['same] (indicating the relative current
directory). For Windows paths, if @scheme[base] is a drive
specification (with or without a trailing slash) the first
The @scheme[base] and each @scheme[sub] must be either a relative
path, the symbol @indexed-scheme['up] (indicating the relative parent
directory), or the symbol @indexed-scheme['same] (indicating the
relative current directory). For Windows paths, if @scheme[base] is a
drive specification (with or without a trailing slash) the first
@scheme[sub] can be an absolute (driveless) path. For all platforms,
the last @scheme[sub] can be a filename.

View File

@ -30,6 +30,8 @@
"Libraries")
(make-sec 'foreign
"Low-Level APIs")
(make-sec 'legacy
"Legacy Languages and Libraries")
(make-sec 'other
"Other")))
@ -81,7 +83,7 @@
(car new-cat)
new-cat)])
(case the-cat
[(getting-started language tool library foreign other omit)
[(getting-started language tool library foreign legacy other omit)
the-cat]
[else
(fprintf (current-error-port)

View File

@ -5,6 +5,7 @@
"private/doc-path.ss"
scheme/class
scheme/file
scheme/fasl
setup/main-collects
scribble/base-render
scribble/struct
@ -301,6 +302,10 @@
(and (pair? cat)
(eq? (car cat) 'omit))))
(define (read-out-sxref)
(fasl->s-exp (current-input-port)))
(define ((get-doc-info only-dirs latex-dest auto-main? auto-user? with-record-error) doc)
(let* ([info-out-file (build-path (or latex-dest (doc-dest-dir doc)) "out.sxref")]
[info-in-file (build-path (or latex-dest (doc-dest-dir doc)) "in.sxref")]
@ -352,7 +357,7 @@
((get-doc-info only-dirs latex-dest auto-main? auto-user?
with-record-error) doc))])
(let* ([v-in (with-input-from-file info-in-file read)]
[v-out (with-input-from-file info-out-file read)])
[v-out (with-input-from-file info-out-file read-out-sxref)])
(unless (and (equal? (car v-in) (list vers (doc-flags doc)))
(equal? (car v-out) (list vers (doc-flags doc))))
(error "old info has wrong version or flags"))
@ -383,7 +388,7 @@
[ri (send renderer resolve (list v) (list dest-dir) ci)]
[out-v (and info-out-time
(with-handlers ([exn? (lambda (exn) #f)])
(let ([v (with-input-from-file info-out-file read)])
(let ([v (with-input-from-file info-out-file read-out-sxref)])
(unless (equal? (car v) (list vers (doc-flags doc)))
(error "old info has wrong version or flags"))
v)))]
@ -505,24 +510,24 @@
(when (verbose) (printf " [Caching ~a]\n" info-file))
(with-output-to-file info-file #:exists 'truncate/replace
(lambda ()
(write ((sel (lambda ()
(list (list (info-vers info) (doc-flags doc))
(info-sci info)
(info-provides info)))
(lambda ()
(list (list (info-vers info) (doc-flags doc))
(info-undef info)
(map (lambda (i)
(path->rel (doc-src-file (info-doc i))))
(info-deps info))
(info-searches info))))))))))
(sel (lambda ()
(list (list (info-vers info) (doc-flags doc))
(info-sci info)
(info-provides info)))
(lambda ()
(list (list (info-vers info) (doc-flags doc))
(info-undef info)
(map (lambda (i)
(path->rel (doc-src-file (info-doc i))))
(info-deps info))
(info-searches info))))))))
(define (write-out info)
(make-directory* (doc-dest-dir (info-doc info)))
(write- info "out.sxref" (lambda (o i) o)))
(write- info "out.sxref" (lambda (o i) (write-bytes (s-exp->fasl (o))))))
(define (write-in info)
(make-directory* (doc-dest-dir (info-doc info)))
(write- info "in.sxref" (lambda (o i) i)))
(write- info "in.sxref" (lambda (o i) (write (i)))))
(define (rel->path r)
(if (bytes? r)

View File

@ -2,6 +2,7 @@
(require scribble/xref
setup/getinfo
scheme/fasl
"private/doc-path.ss")
(provide load-collections-xref)
@ -45,7 +46,7 @@
(exn-message exn)
(format "~e" exn)))
#f)])
(let ([r (with-input-from-file dest read)])
(let ([r (call-with-input-file* dest fasl->s-exp)])
(cadr r)))))
dests)))
cached-xref))))