24 mzlib/kw

▼ |  | Mz Lib: Legacy Libraries

1 | mzlib/ a-signature
2 | mzlib/ a-unit
3 | mzlib/ async-channel
4 | mzlib/ awk
5 | mzlib/ class
6 | mzlib/ cm
7 | mzlib/ cm-accomplice
8 | mzlib/ cmdline
9 | mzlib/ cml
10 | mzlib/ compat
11 | mzlib/ compile
12 | mzlib/ contract
13 | mzlib/ control
14 | mzlib/ date
15 | mzlib/ deflate
16 | mzlib/ defmacro
17 | mzlib/ etc
18 | mzlib/ file
19 | mzlib/ for
20 | mzlib/ foreign
21 | mzlib/ include
22 | mzlib/ inflate
23 | mzlib/ integer-set
24 | mzlib/ kw
25 | mzlib/ list
26 | mzlib/ match
27 | mzlib/ math
28 | mzlib/ md5
29 | mzlib/ os
30 | mzlib/ pconvert
31 | mzlib/ pconvert-prop
32 | mzlib/ plt-match
33 | mzlib/ port
34 | mzlib/ pregexp
35 | mzlib/ pretty
36 | mzlib/ process
37 | mzlib/ restart
38 | mzlib/ runtime-path
39 | mzlib/ sandbox
40 | mzlib/ sendevent
41 | mzlib/ serialize
42 | mzlib/ shared
43 | mzlib/ string
44 | mzlib/ struct
45 | mzlib/ stxparam
46 | mzlib/ surrogate
47 | mzlib/ tar
48 | mzlib/ thread
49 | mzlib/ trace
50 | mzlib/ traceld
51 | mzlib/ trait
52 | mzlib/ transcr
53 | mzlib/ unit
54 | mzlib/ unit-exptime
55 | mzlib/ unit200
56 | mzlib/ unitsig200
57 | mzlib/ zip
| Bibliography
| Index

► | 24 | mzlib/ kw

24.1 | Required Arguments
24.2 | Optional Arguments
24.3 | Keyword Arguments
24.4 | Rest and Rest-like Arguments
24.5 | Body Argument
24.6 | Mode Keywords
24.7 | Property Lists

On this page:

lambda/ kw
define/ kw
24.1`` Required Arguments
24.2`` Optional Arguments
24.3`` Keyword Arguments
24.4`` Rest and Rest-like Arguments
24.5`` Body Argument
24.6`` Mode Keywords
24.7`` Property Lists
keyword-get

top contents ← prev up next →

(require mzlib/kw) | package: compatibility-lib

> NOTE: This library is deprecated; use racket/base, instead. The Racket base language supports keyword arguments. Using the built-in keyword arguments in Racket is highly recommended.

> > > The lambda and procedure-application forms of scheme/base support keyword arguments, and it is not compatible with the mzlib/kw library.

> syntax (lambda/kw kw-formals body ...+)
> syntax (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 |  | = |  | #:rest id
> |  | | |  | #:other-keys id
> |  | | |  | #:other-keys+body id
> |  | | |  | #:all-keys id
> |  | | |  | #:body kw-formals
> |  | | |  | #:allow-other-keys
> |  | | |  | #:forbid-other-keys
> |  | | |  | #:allow-duplicate-keys
> |  | | |  | #:forbid-duplicate-keys
> |  | | |  | #:allow-body
> |  | | |  | #:forbid-body
> |  | | |  | #:allow-anything
> |  | | |  | #:forbid-anything
> head |  | = |  | id
> |  | | |  | (head . kw-formals)

Like 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, lambda/kw expands to a plain lambda, so lambda/kw is suitable for a language module that will use it to replace lambda. Also, when used with only optionals, the resulting procedure is similar to opt-lambda (but a bit faster).

In addition to lambda/kw, define/kw is similar to define, except that the formals are as in lambda/kw. Like define, this form can be used with nested parenthesis for curried functions (the MIT-style generalization of define).

The syntax of lambda/kw is the same as 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 #:optional marker, then a keyword section that is marked by #: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 ids must be unique.

The following sections describe each part of the kw-formals.

#### 24.1`` Required Arguments🔗ℹ

Required arguments correspond to ids that appear before any keyword marker in the argument list. They determine the minimum arity of the resulting procedure.

#### 24.2`` Optional Arguments🔗ℹ

The optional-arguments section follows an #:optional marker in the 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 #f is the default.

The default expression’s environment includes all previous arguments, both required and optional names. With k optionals after n required arguments, and with no keyword arguments or rest-like arguments, the resulting procedure accept between n and n+k arguments, inclusive.

The treatment of optionals is efficient, with an important caveat: default expressions appear multiple times in the resulting case-lambda. For example, the default expression for the last optional argument appears k-1 times (but no expression is ever evaluated more than once in a procedure call). This expansion risks exponential blow-up is if lambda/kw is used in a default expression of a lambda/kw, etc. The bottom line, however, is that 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.

#### 24.3`` Keyword Arguments🔗ℹ

A keyword argument section is marked by a #: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 #:x is called with #:x 1, then the optional arguments get their default values and the keyword argument is bound to 1. (The traditional behavior would bind #:x and 1 to the two optional arguments.) When the same procedure is called with 1 #:x 2, the first optional argument is bound to 1, the second optional argument is bound to its default, and the keyword argument is bound to 2. (The traditional behavior would report an error, because 2 is provided where #: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 #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 Mode Keywords), the value after the first occurrence is used for the variable:

Example:

> > ((lambda/kw (#:key x [y 2] [z #:zz 3] #:allow-duplicate-keys)
> (list x y z))
> #:x 'x #:zz 'z #:x "foo")
> '(x 2 z)

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 Mode Keywords for information on when duplicate or unknown keywords are allowed at a call site.

#### 24.4`` Rest and Rest-like Arguments🔗ℹ

The last 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 id to bind:

- #: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 kw-formals only if no other meta-keywords are specified, since it is not clear whether it should specify the same binding as a #:rest or as a #:body. The dot notation is allowed without meta-keywords to make the lambda/kw syntax compatible with lambda.

- #:body — The variable is bound to all arguments after keyword–value pairs. (This is different from Common Lisp’s &body, which is a synonym for &rest.) More generally, a #:body specification can be followed by another kw-formals, not just a single id; see Body Argument for more information.

- #: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 #:rest argument. (If no #:body arguments are declared, then #:all-keys binds the same as #:rest.) See also keyword-get.

- #:other-keys — The variable is bound like an #:all-keys variable, except that all keywords specified in the 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 #:other-keys binding.

- #:other-keys+body — the variable is bound like a #:rest variable, except that all keywords specified in the 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 #:other-keys+body binding. (When no #:body variables are specified, then #:other-keys+body is the same as #:other-keys.)

In the following example, all rest-like arguments are used and have different bindings:

Example:

> > ((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)
> '((#:z 1 #:x 2 2 3 4) (#:z 1 2 3 4) (2 3 4) (#:z 1 #:x 2) (#:z 1))

Note that the following invariants always hold:

- rest = (append all-keys body)

- other-keys+body = (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 #:other-keys (or #:other-keys+body). The Common Lisp approach is to specify :allow-other-keys, so that the second procedure call will not cause an error due to unknown keywords, but the :allow-other-keys approach risks confusing the two layers of keywords.

#### 24.5`` Body Argument🔗ℹ

The most notable divergence from Common Lisp in lambda/kw is the #:body argument, and the fact that it is possible at a call site to pass plain values after the keyword-value pairs. The #: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 #:body argument:

Examples:

> > (define/kw (mathop #:key [op +] #:body b)
> (apply op b))
> > (mathop 1 2 3)
> 6
> > (mathop #:op max 1 2 3)
> 3

(Note that the first body value cannot itself be a keyword.)

A #:body declaration works as an arbitrary kw-formals, not just a single variable like b in the above example. For example, to make the above mathop work only on three arguments that follow the keyword, use (x y z) instead of b:

Example:

> > (define/kw (mathop #:key [op +] #:body (x y z))
> (op x y z))

In general, #:body handling is compiled to a sub procedure using lambda/kw, so that a procedure can use more then one level of keyword arguments. For example:

Examples:

> > (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)
> 48.0

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 ~body suffix:

Example:

> > (mathop #:op * 2 4)
> mathop~body: arity mismatch;
> the expected number of arguments does not match the given
> number
> expected: at least 3
> given: 2

#### 24.6`` Mode Keywords🔗ℹ

Finally, the argument list of a lambda/kw can contain keywords that serve as mode flags to control error reporting.

- #:allow-other-keys — The keyword-value sequence at the call site can include keywords that are not listed in the keyword part of the lambda/kw form.

- #:forbid-other-keys — The keyword-value sequence at the call site cannot include keywords that are not listed in the keyword part of the lambda/kw form, otherwise the exn:fail:contract exception is raised.

- #:allow-duplicate-keys — The keyword-value list at the call site can include duplicate values associated with same keyword, the first one is used.

- #:forbid-duplicate-keys — The keyword-value list at the call site cannot include duplicate values for keywords, otherwise the exn:fail:contract exception is raised. This restriction applies only to keywords that are listed in the keyword part of the lambda/kw form — if other keys are allowed, this restriction does not apply to them.

- #:allow-body — Body arguments can be specified at the call site after all keyword-value pairs.

- #:forbid-body — Body arguments cannot be specified at the call site after all keyword-value pairs.

- #:allow-anything — Allows all of the above, and treat a single keyword at the end of an argument list as a #:body, a situation that is usually an error. When this is used and no rest-like arguments are used except #:rest, an extra loop is saved and calling the procedures is faster (around 20%).

- #: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:

- The default is to allow other keys if a #:rest, #:other-keys+body, #:all-keys, or #:other-keys variable is declared (and an #:other-keys declaration requires allowing other keys).

- The default is to allow duplicate keys if a #:rest or #:all-keys variable is declared.

- The default is to allow body arguments if a #:rest, #:body, or #:other-keys+body variable is declared (and a #:body argument requires allowing them).

Here’s an alternate specification, which maps rest-like arguments to the behavior that they imply:

- #:rest: Everything is allowed (a body, other keys, and duplicate keys);

- #:other-keys+body: Other keys and body are allowed, but duplicates are not;

- #:all-keys: Other keys and duplicate keys are allowed, but a body is not;

- #:other-keys: Other keys must be allowed (on by default, cannot use with #:forbid-other-keys), and duplicate keys and body are not allowed;

- #:body: Body must be allowed (on by default, cannot use with #:forbid-body) and other keys and duplicate keys and body are not allowed;

- Except for the previous two “must”s, defaults can be overridden by an explicit #:allow-... or a #:forbid-... mode.

#### 24.7`` Property Lists🔗ℹ

> procedure (keyword-get args kw not-found) → any
> args : (listof (cons/c keyword? any/c))
> kw : keyword?
> not-found : (-> 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 lambda/kw to search for keyword values.

The args list is scanned from left to right, if the keyword is found, then the next value is returned. If the kw was not found, then the not-found thunk is used to produce a value by applying it. If the kw was not found, and not-found thunk is not given, #f is returned. (No exception is raised if the args list is imbalanced, and the search stops at a non-keyword value.)

top contents ← prev up next →