3.5 Solution for Exercise 18
Like minimatch1, the minimatch macro needs a private
variable for the value being matched. It needs a second private
variable to represent the failure action. Consider the pattern
(cons 'a 'b). The whole pattern can fail, because the value
is not a pair; the first sub-pattern can fail; and the second
sub-pattern can fail. There must be three occurrences of the same
failure action—
The main macro, minimatch, just sets up the private variable for the value to be matched. The first helper macro, minimatch-clauses, recurs through the clauses and sets up private variables for failure actions. The second helper macro is similar to the helper macro for minimatch1, but it takes an extra argument, a failure expression, that it uses instead of directly calling error.
(define-syntax minimatch (syntax-rules () [(minimatch val-expr clause ...) (let ([v val-expr]) (minimatch-clauses v clause ...))])) (define-syntax minimatch-clauses (syntax-rules () [(minimatch-clauses v) (error 'minimatch "match failed")] [(minimatch-clauses v [pattern1 result-expr1] clause ...) (let ([fail (lambda () (minimatch* v clause ...))]) (minimatch1/fail v pattern1 result-expr1 (fail)))])) (define-syntax minimatch1/fail (syntax-rules (cons quote) [(minimatch1/fail v (quote datum) result-expr fail-expr) (if (equal? v (quote datum)) result-expr fail-expr)] [(minimatch1/fail v (cons first-pattern rest-pattern) result-expr fail-expr) (if (pair? v) (let ([first-var (car v)] [rest-var (cdr v)]) (minimatch1/fail first-var first-pattern (minimatch1/fail rest-var rest-pattern result-expr fail-expr) fail-expr)) fail-expr)] [(minimatch1/fail v variable-id result-expr fail-expr) (let ([variable-id v]) result-expr)]))