etc.ss: Useful Procedures and Syntax
To load: (require (lib "etc.ss"))
(
SYNTAX
begin-lifted
expr ···1
)
Lifts the expr
s so that they are evaluated once at the ``top
level'' of the current context, and the result of the last expr
is used for every evaluation of the 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
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 define-syntax
, 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
local-expand/capture-lifts
) for the expressions that they
enclose.
(
SYNTAX
begin-with-definitions
defn-or-expr ···
)
Supports a mixture of expressions and mutually recursive definitions,
much like a module
body. Unlike in a module
,
however, syntax definitions cannot be used to generate other
immediate definitions (though they can be used for expressions).
The result of the begin-with-definitions
form is the result of
the last defn-or-expr
if it is an expression, void
otherwise. If no defn-or-expr
is provided (after flattening
begin
forms), the result is void.
(boolean=?
bool1 bool2
)
PROCEDURE
Returns #t
if bool1
and bool2
are both #t
or
both #f
, and returns #f
otherwise. If either
bool1
or bool2
is not a Boolean, the
exn:fail:contract
exception is raised.
Creates a list of n
elements by applying f
to the integers
from 0
to n
- 1
in order, where n
is a
non-negative integer. If r
is the resulting list, (
is
list-ref
r i)(
.f
i
)
Creates a string of length n
by applying f
to the integers
from 0
to n
- 1
in order, where n
is a
non-negative integer and f
returns a character for the n
invocations. If r
is the resulting string, (
is string-ref
r i)(
.f
i
)
Creates a vector of n
elements by applying f
to the
integers from 0
to n
- 1
in order,
where n
is a non-negative integer. If r
is the resulting
vector, (
is vector-ref
r i)(
.f
i
)
Returns a procedure that composes the given functions, applying the
last f
first and the first f
last. The composed functions
can consume and produce any number of values, as long as each
function produces as many values as the preceding function consumes.
For example, (compose
returns the equivalent
of f
g
)(lambda l (
.call-with-values
(lambda () (apply
g l)) f))
(
SYNTAX
define-syntax-set
)(
identifier ···)
defn ···
This form is similar to define-syntaxes
, but instead of a
single body expression, a sequence of definitions follows the
sequence of defined identifiers. For each identifier
, the
defn
s should include a definition for
. The value for
identifier
/proc
is used as the (expansion-time) value
for identifier
/procidentifier
.
The define-syntax-set
form is especially useful for defining
a set of syntax transformers that share helper functions.
Example:
(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-syntaxcall/cc
))) (define let-current-escape-continuation/proc (mk (quote-syntaxcall/ec
))))
(
SYNTAX
evcase
key-expr
)(
value-expr body-expr ···)
···1
The evcase
form is similar to case
, except that expressions
are provided in each clause instead of a sequence of data. After
key-expr
is evaluated, each value-expr
is evaluated until
a value is found that is eqv?
to the key value; when a matching
value is found, the corresponding body-expr
s are evaluated and
the value(s) for the last is the result of the entire evcase
expression.
A value-expr
can be the special identifier else
. This
identifier is recognized as in case
(see section 2.3 in PLT MzScheme: Language Manual).
Boolean false.
Returns v
.
(
SYNTAX
let+
clause body-expr ···1
)
A new 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 let
, except
each clause has an additional keyword tag before the binding
variables.
Each clause
has one of the following forms:
(
bindsval
target expr)target
non-recursively toexpr
.(rec target expr)
bindstarget
recursively toexpr
.(
thevals
(target expr) ···)target
s are bound to theexpr
s. The environment of theexpr
s is the environment active before this clause.(
therecs
(variable expr) ···)targets
s are bound to theexpr
s. The environment of theexpr
s includes all of thetargets
s.(_ expr ···)
evaluates theexpr
s without binding any variables.
The clauses bind left-to-right. Each target
above can either be
an identifier or (
. In the latter
case, multiple values returned by the corresponding expression are
bound to the multiple variables.values
variable ···)
Examples:
(let+ ([val
(values
x y) (values
1 2)]) (list
x y)) ; =>'(1 2)
(let ([x 1]) (let+ ([val
x 3] [val
y x]) y)) ; =>3
(
SYNTAX
local
)(
definition ···)
body-expr ···1
This is a binding form similar to letrec
, except that each
definition
is a define-values
expression (after
partial macro expansion). The body-expr
s are evaluated in the
lexical scope of these definitions.
(loop-until
start done? next f
)
PROCEDURE
Repeatedly invokes the f
procedure until the
done?
procedure returns #t
. The procedure is
best described by its implementation:
(define loop-until
(lambda (start done? next f)
(let loop ([i start])
(unless (done? i)
(f i)
(loop (next i))))))
(namespace-defined?
symbol
)
PROCEDURE
Returns #t
if
would
return a value for namespace-variable-value
symbol
, #f
otherwise. See
section 8.2 in PLT MzScheme: Language Manual for further information.
(
SYNTAX
nand
expr ···
)
Returns (
.not
(and expr ···))
(
SYNTAX
nor
expr ···
)
Returns (
.not
(or expr ···))
(
SYNTAX
opt-lambda
formals body-expr ···1
)
The opt-lambda
form is like lambda
, except that default
values are assigned to arguments (C++-style). Default values are
defined in the formals
list by replacing each variable
by
[
. If a variable
has a default value expression, then all (non-aggregate) variables
after it must have default value expressions. A final aggregate
variable can be used as in variable
default-value-expression
]lambda
, but it cannot be given a
default value. Each default value expression is evaluated only if it
is needed. The environment of each default value expression includes
the preceding arguments.
For example:
(define f
(opt-lambda (a [b (add1
a)] . c)
...))
In the example, f
is a procedure which takes at least one
argument. If a second argument is specified, it is the value of
b
, otherwise b
is (
. If more than two
arguments are specified, then the extra arguments are placed in a new
list that is the value of add1
a)c
.
See also section 25 for a library that generalizes both optional and keyword arguments.
(
SYNTAX
recur
name bindings body-expr ···1
)
This is equivalent to a named let
: (let name bindings body-expr ···1)
.
(
SYNTAX
rec
name value-expr
)
This is equivalent to a letrec
expression that returns its
binding: (letrec ((name value-expr)) name)
.
(
SYNTAX
rec
(name id ...) expr
)
(
SYNTAX
rec
(name id ... . id) expr
)
These two are shorthands for the use of rec
above,
much like define
allows shorthands for defining
procedures. In particular the first one expands into a use
of rec
bound to a lambda
expression whose
body is expr
and whose parameters are
id ...
. The second is like the first, but with a rest argument.
(symbol=?
symbol1 symbol2
)
PROCEDURE
Returns #t
if symbol1
and symbol2
are equivalent
(as determined by eq?
), #f
otherwise. If either
symbol1
or symbol2
is not a symbol, the
exn:fail:contract
exception is raised.
(
SYNTAX
this-expression-source-directory
)
Note: see section 40 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. The source expression's
file is determined through source location information associated with
the syntax, if it is present. Otherwise,
current-load-relative-directory
is used if it is not
#f
, and current-directory
is used if all else fails.
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.
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. A simple (bytes->path #"...")
expression is used, unless the directory is within the result of
find-collects-dir
from (
, in
which case the expansion records the path relative to
lib
"dirs.ss" "setup")(find-collects-dir)
and then reconstructs it using
(find-collects-dir)
at run time.
(
SYNTAX
this-expression-file-name
)
Expands to an expression that evaluates to the file name of the source
expression. The source expression's file name is determined through source
location information associated with the syntax if it is present. If this
information is missing, or is not a path (e.g., for a standard-input
expression), then #f
will be used instead.
Boolean true.
(
SYNTAX
hash-table
'flag ...(key value) ...
)
This creates a new hash-table providing the quoted flags (if any)
to
, and make each of the keys map to the
corresponding values. (Flags must be specified by a quoted form.)make-hash-table