On this page:
define-match-expander-from-match-and-make
define-match-expander-attenuated
match/  c

9 Utilities for Match Expanders🔗ℹ

 (require lathe-comforts/match) package: lathe-comforts-lib

syntax

(define-match-expander-from-match-and-make
  new-name-id match-name-id make-id-name-id make-list-name-id)
Defines new-name-id as a syntax that expands into a call to match-name-id if it’s used a match expander, make-id-name-id if it’s used as an standalone identifier in an expression context, and make-list-name-id if it’s used at the beginning of a list in an expression context.

syntax

(define-match-expander-attenuated
  new-name-id old-name-id [arg-id arg/c-expr] ... guard-expr)
 
  arg/c-expr : contract?
Defines new-name-id as a syntax that acts as a match expander which takes one subform for each arg-id and expands into a pattern using old-name-id with the same number of subforms.

When the syntax defined this way used as an expression syntax with one subexpression for each arg/c-expr, it first executes each subexpression, projects them each through the corresponding arg/c-expr contract, and evaluates guard-expr with arg-id bound to those projections. If the result of guard-expr is #f, a precondition representing to this guard fails, raising an exn:fail:contract exception. Otherwise, this returns the result of (old-name-id arg-id ...).

When the syntax defined this way is used as an identifier, it returns a function that performs the expression syntax behavior when it’s called.

When the syntax defined this way is used as a match expander with one pattern for each arg-id, it first tries to match the same arguments according to (old-name-id arg-id ...), and it fails if that pattern fails. Then it tries to check each of the arg/c-expr contracts’ contract-first-order-passes? behavior against the respective argument value, and it fails if any of those fails. Then it projects the arguments through those contracts, and it attempts to check the guard-expr with those projections, failing if the guard-expr returns #f. If it hasn’t failed yet, it proceeds to match those projections according to the patterns given at the call site.

syntax

(match/c name-id arg/c-expr ...)

 
  arg/c-expr : contract?
Returns a contract that recognizes a value if it matches a pattern of the form (name-id arg-id ...), where each arg-id is an identifier, and only as long as each value bound to a arg-id this way abides by the respective arg/c-expr contract.

The value’s projection is computed by taking the projections of each of the arguments and then executing (name-id arg-id ...), where this time each arg-id is an identifier already bound to the argument’s projection value. For some match patterns, this may cause substantial changes to the value when projected by this contract: If name-id is vector, it changes immutable vectors to mutable ones. If name-id is a structure type name, it changes instances of subtypes of name-id into instances of name-id itself.

Unlike struct/c (but like istruct/c), this works even when name-id is an immutable structure type name and the arg/c-expr contracts contain one or more impersonator contracts.