6.7.4.2 (ice-9 optargs)

Before Guile 2.0, lambda* and define* were implemented using macros that processed rest list arguments. This was not optimal, as calling procedures with optional arguments had to allocate rest lists at every procedure invocation. Guile 2.0 improved this situation by bringing optional and keyword arguments into Guile’s core.

However there are occasions in which you have a list and want to parse it for optional or keyword arguments. Guile’s (ice-9 optargs) provides some macros to help with that task.

The syntax let-optional and let-optional* are for destructuring rest argument lists and giving names to the various list elements. let-optional binds all variables simultaneously, while let-optional* binds them sequentially, consistent with let and let* (see Local Variable Bindings).

library syntax: let-optional rest-arg (binding …) body1 body2 …
library syntax: let-optional* rest-arg (binding …) body1 body2 …

These two macros give you an optional argument interface that is very Schemey and introduces no fancy syntax. They are compatible with the scsh macros of the same name, but are slightly extended. Each of binding may be of one of the forms var or (var default-value). rest-arg should be the rest-argument of the procedures these are used from. The items in rest-arg are sequentially bound to the variable names are given. When rest-arg runs out, the remaining vars are bound either to the default values or #f if no default value was specified. rest-arg remains bound to whatever may have been left of rest-arg.

After binding the variables, the expressions body1 body2 … are evaluated in order.

Similarly, let-keywords and let-keywords* extract values from keyword style argument lists, binding local variables to those values or to defaults.

library syntax: let-keywords args allow-other-keys? (binding …) body1 body2 …
library syntax: let-keywords* args allow-other-keys? (binding …) body1 body2 …

args is evaluated and should give a list of the form (#:keyword1 value1 #:keyword2 value2 …). The bindings are variables and default expressions, with the variables to be set (by name) from the keyword values. The body1 body2 … forms are then evaluated and the last is the result. An example will make the syntax clearest,

(define args '(#:xyzzy "hello" #:foo "world"))

(let-keywords args #t
      ((foo  "default for foo")
       (bar  (string-append "default" "for" "bar")))
  (display foo)
  (display ", ")
  (display bar))
-| world, defaultforbar

The binding for foo comes from the #:foo keyword in args. But the binding for bar is the default in the let-keywords, since there’s no #:bar in the args.

allow-other-keys? is evaluated and controls whether unknown keywords are allowed in the args list. When true other keys are ignored (such as #:xyzzy in the example), when #f an error is thrown for anything unknown.

(ice-9 optargs) also provides some more define* sugar, which is not so useful with modern Guile coding, but still supported: define*-public is the lambda* version of define-public; defmacro* and defmacro*-public exist for defining macros with the improved argument list handling possibilities. The -public versions not only define the procedures/macros, but also export them from the current module.

library syntax: define*-public formals body1 body2 …

Like a mix of define* and define-public.

library syntax: defmacro* name formals body1 body2 …
library syntax: defmacro*-public name formals body1 body2 …

These are just like defmacro and defmacro-public except that they take lambda*-style extended parameter lists, where #:optional, #:key, #:allow-other-keys and #:rest are allowed with the usual semantics. Here is an example of a macro with an optional argument:

(defmacro* transmogrify (a #:optional b)
  (a 1))