1.2.5 More Keyword Arguments

1.2 Examples
top
up

1.2.5More Keyword ArgumentsπŸ”— i

This section shows how to express the syntax of struct ’s optional keyword arguments using syntax-parse patterns.

The part of struct ’s syntax that is difficult to specify is the sequence of struct options. Let’s get the easy part out of the way first.

(pattern (~seq super:id))
(pattern (~seq )))
> (define-syntax-class field-option
(pattern #:mutable)
(pattern #:auto))
(pattern field:id
#:with(option... )'())
(pattern [field:idoption:field-option... ]))

Given those auxiliary syntax classes, here is a first approximation of the main pattern, including the struct options:
(struct name:idsuper:maybe-super(field:field... )
(~alt (~seq #:mutable)
(~seq #:supersuper-expr:expr)
(~seq #:inspectorinspector:expr)
(~seq #:auto-valueauto:expr)
(~seq #:guardguard:expr)
(~seq #:propertyprop:exprprop-val:expr)
(~seq #:transparent)
(~seq #:prefab)
(~seq #:constructor-nameconstructor-name:id)
(~seq #:extra-constructor-nameextra-constructor-name:id)
(~seq #:omit-define-syntaxes)
(~seq #:omit-define-values))
... )
The fact that expr does not match keywords helps in the case where the programmer omits a keyword’s argument; instead of accepting the next keyword as the argument expression, syntax-parse reports that an expression was expected.

There are two main problems with the pattern above:
  • There’s no way to tell whether a zero-argument keyword like #:mutable was seen.

  • Some options, like #:mutable, should appear at most once.

The first problem can be remedied using ~and patterns to bind a pattern variable to the keyword itself, as in this sub-pattern:

(~seq (~and #:mutablemutable-kw))

The second problem can be solved using repetition constraints:
(struct name:idsuper:maybe-super(field:field... )
(~alt (~optional (~seq (~and #:mutablemutable-kw)))
(~optional (~seq #:supersuper-expr:expr))
(~optional (~seq #:inspectorinspector:expr))
(~optional (~seq #:auto-valueauto:expr))
(~optional (~seq #:guardguard:expr))
(~seq #:propertyprop:exprprop-val:expr)
(~optional (~seq (~and #:transparenttransparent-kw)))
(~optional (~seq (~and #:prefabprefab-kw)))
(~optional (~seq #:constructor-nameconstructor-name:id))
(~seq #:extra-constructor-nameextra-constructor-name:id))
(~seq (~and #:omit-define-syntaxesomit-def-stxs-kw)))
(~optional (~seq (~and #:omit-define-valuesomit-def-vals-kw))))
... )
The ~optional repetition constraint indicates that an alternative can appear at most once. (There is a ~once form that means it must appear exactly once.) In struct ’s keyword options, only #:property may occur any number of times.

There are still some problems, though. Without additional help, ~optional does not report particularly good errors. We must give it the language to use, just as we had to give descriptions to sub-patterns via syntax classes. Also, some related options are mutually exclusive, such as #:inspector, #:transparent, and #:prefab.

(struct name:idsuper:maybe-super(field:field... )
(~or* (~seq #:inspectorinspector:expr)
(~seq (~and #:transparenttransparent-kw))
(~seq (~and #:prefabprefab-kw)))
#:name"#:inspector, #:transparent, or #:prefab option")
(~optional (~seq (~and #:mutablemutable-kw))
#:name"#:mutable option")
(~optional (~seq #:supersuper-expr:expr)
#:name"#:super option")
(~optional (~seq #:auto-valueauto:expr)
#:name"#:auto-value option")
(~optional (~seq #:guardguard:expr)
#:name"#:guard option")
(~seq #:propertyprop:exprprop-val:expr)
(~optional (~seq #:constructor-nameconstructor-name:id)
#:name"#:constructor-name option")
(~seq #:extra-constructor-nameextra-constructor-name:id)
#:name"#:extra-constructor-name option")
(~optional (~seq (~and #:omit-define-syntaxesomit-def-stxs-kw))
#:name"#:omit-define-syntaxes option")
(~optional (~seq (~and #:omit-define-valuesomit-def-vals-kw))
#:name"#:omit-define-values option"))
... )
Here we have grouped the three incompatible options together under a single ~optional constraint. That means that at most one of any of those options is allowed. We have given names to the optional clauses. See ~optional for other customization options.

Note that there are other constraints that we have not represented in the pattern. For example, #:prefab is also incompatible with both #:guard and #:property. Repetition constraints cannot express arbitrary incompatibility relations. The best way to handle such constraints is with a side condition using #:fail-when.

top
up

AltStyle γ«γ‚ˆγ£γ¦ε€‰ζ›γ•γ‚ŒγŸγƒšγƒΌγ‚Έ (->γ‚ͺγƒͺγ‚ΈγƒŠγƒ«) /