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)
syntax
(define-match-expander-attenuated new-name-id old-name-id [arg-id arg/c-expr] ... guard-expr)
arg/c-expr : contract?
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.
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.