Up: simple-match   [Index]


1.5.1 Pattern matcher generator

The following bindings are exported by the library (vicare languae-extensions simple-match). The auxiliary syntaxes are the bindings exported by the library (vicare), which are reexported by this library.

Syntax: match ?expr ?clause ...
Auxiliary Syntax: =>
Auxiliary Syntax: else
Auxiliary Syntax: let
Auxiliary Syntax: quote
Auxiliary Syntax: quasiquote
Auxiliary Syntax: syntax
Auxiliary Syntax: and
Auxiliary Syntax: or
Auxiliary Syntax: not
Auxiliary Syntax: apply
Auxiliary Syntax: eval
Auxiliary Syntax: ...
Auxiliary Syntax: _

Match the symbolic expression ?expr against the ?clause arguments. Each clause must have one of the formats:

(?pattern ?body ...)
(?pattern (=> ?next) ?body ...)
(else ?body0 ?body ...)

?expr is evaluated once and the result is matched against each ?pattern in turn; the first to succeed causes the corresponding ?body forms to be evaluated as in begin, and the remaining patterns are ignored. However, if the ?next identifier is labeled, it may be used as a continuation to continue matching, allowing for additional runtime tests on the pattern.

A clause with no body (?pattern), when matching the input expression, causes the evaluation of (values) (which returns zero values).

The syntax for the patterns is:

_

The literal underscore is the wildcard: it matches anything, it does not reference any variable.

(match "ciao"
  (_            #t)
  (else         #f))
⇒ #t

(match '(1 2 3)
  (_            #t)
  (else         #f))
⇒ #t

(match '(1 2 3)
  ((_ _ _)      #t)
  (else         #f))
⇒ #t

(match '(1 2 3)
  ((_ 2 _)      #t)
  (else         #f))
⇒ #t

(match '(1 2 3)
  ((_ 0 _)      #t)
  (else         #f))
⇒ #f
?datum

Matches if the input expression equals ?datum. The pattern ?datum can be a boolean, character, fixnum, bignum, ratnum, flonum, cflonum, compnum, string or bytevector; such data is compared to the input expression using type–specific predicates and unsafe accessors.

(match 1
  (1            #t)
  (else         #f))
⇒ #t
?variable

Variable reference: it matches the value bound to ?variable using equal?.

(let ((X 1))
  (match 1
    (X          #t)
    (else       #f)))
⇒ #t

(let ((X 1))
  (match 1
    (X          X)
    (else       #f)))
⇒ 1
(let ?variable)

Bind the value of the input expression to ?variable, which must be an identifier; the variable is immediately available to be referenced in the following subpatterns. The empty let pattern is a syntax error; the let pattern with multiple subpatterns is a syntax error, with the exception of the variable with ellipsis.

(match 1
  ((let X)      X)
  (else         #f))
⇒ 1

(match 1
  ((let X)      #\A)
  (else         #f))
⇒ #\A

(match '(1)
  ((let X)      X)
  (else         #f))
⇒ (1)

(match '(1)
  (((let X))    X)
  (else         #f))
⇒ 1

(match '(1 2 3)
  (((let X) (let Y) (let Z))
   (vector X Y Z))
  (else #f))
⇒ #(1 2 3)

(match '(1 2)
  (((let X) (let Y) (let Z))
   (vector X Y Z))
  (else #f))
⇒ #f

(match '(1 (2 3))
  (((let X) (let X) (let X))
   X)
  (else #f))
⇒ 3

(match 123
  ((and (let X) (eval (positive? X)))
   X)
  (else #f))
⇒ 123

(match '(1 2 3)
  (((and (apply number?)
         (let N1))
    . (and (apply (lambda (obj)
                    (for-all number? obj)))
           (let N)))
   (vector N1 N))
  (else #f))
⇒ #(1 (2 3))
(let ?variable ...)

This pattern can appear only as last subpattern of a list or vector pattern. Bind the rest of the input expression to ?variable, which must be an identifier, as a list; the variable is immediately available to be referenced in the following subpatterns.

(match '(1 2 3 4 5)
  (((let X) (let Y) (let Z ...))
   (vector X Y Z))
  (else #f))
⇒ #(1 2 (3 4 5))

(match '(1 2)
  (((let X) (let Y) (let Z ...))
   (vector X Y Z))
  (else #f))
⇒ #(1 2 ())

(match '(1 2 . 3)
  (((let X) (let Y) (let Z ...))
   (vector X Y Z))
  (else #f))
⇒ #f

(match '(1 2 3 4 . 5)
  (((let X) (let Y) (let Z ...))
   (vector X Y Z))
  (else #f))
⇒ #f

(match '(1 2 3)
  ((let id ...)         #\A)
   (else                #\B))
error→ &syntax

(match '(1 2 3 4)
  (((and (apply number?) (let N1))
    (and (apply number?) (let N))
    ...)
   (vector N1 N))
  (else #f))
⇒ (#(1 2) #(1 3) #(1 4))
(quote ?datum)

A quoted datum; it matches if it is equal to the input expression according to equal?. As special case: if ?datum is a symbol, it is compared to the input expression with eq?.

(match '(1 2 3)
  ('(1 2 3)     #t)
  (else         #f))
⇒ #t

(match '(1 X 3)
  ('(1 X 3)     #t)
  (else         #f))
⇒ #t

(match '(1 X 3)
  ((1 'X 3)     #t)
  (else         #f))
⇒ #t
(quasiquote ?datum)

A quasiquoted datum; it matches if it the result of the quasiquotation is equal to the input expression according to equal?.

(let ((X 2))
  (match '(2 2)
    (`(1 ,X)    #\A)
    (`(2 ,X)    #\B)
    (`(3 ,X)    #\C)
    (else       #f)))
⇒ #\B
(syntax ?pattern)
(syntax ?pattern (?literal …))

A syntax-case pattern with optional literal identifiers; the matching code is built as follows:

(syntax-case input-expr (?literal …)
  (?pattern
   #;success)
  (_
   #;failure))

the body of the clause can access pattern variables in the same way they are accessed from the output expression of a syntax-case use.

(match '(1 2 3)
  ((syntax (1 2 3))
   #t)
  (else #f))
⇒ #t

;;match an identifier
(let ((ciao #f))
  (match #'ciao
    ((syntax ciao (ciao))
     #t)
    (else #f)))
⇒ #t

;;match pattern variables
(let ((ciao #f))
  (match '(1 2 3)
    ((syntax (a b c))
     (syntax->datum #'b))
    (else #f)))
⇒ 2
()
(?pattern1 --- ?patternN)

Null or proper list of N elements.

(match '()
  (()
   #t)
  (else #f))
⇒ #t

(match '(1 2 3)
  ((1 2 3)
   #t)
  (else #f))
⇒ #t
(?pattern1 --- ?patternN . ?patternN+1)

Improper list of N or more elements.

(match '(1 . 2)
  ((1 . 2)
   #t)
  (else #f))
⇒ #t

(match '(1 2 3 . 4)
  ((1 2 3 . 4)
   #t)
  (else #f))
⇒ #t
(?pattern1 --- ?patternN ?patternN+1 ...)

List of N or more elements with terminating ellipsis; each element of remainder must match ?patternN+1. The body is evaluated once for every element matched by the pattern before the ellipsis and the results are returned in a list.

(match '(1)
  ((1 ...)      #t)
  (else         #f))
⇒ (#t)

(match '(1 1)
  ((1 ...)      #t)
  (else         #f))
⇒ (#t #t)

(match '(1 1 1)
  ((1 ...)      #t)
  (else         #f))
⇒ (#t #t #t)

(match '(1 2)
  ((0 1 ...)    #t)
  (else         #f))
⇒ #f

(match '(1 2 3)
  (((let X) ...)
   (+ 10 X))
  (else #f))
⇒ (11 12 13)

(match '(1 2 3)
  (((let X) (let Y) ...)
   (vector X Y))
  (else #f))
⇒ (#(1 2) #(1 3))

(match '((1 2 3) (4 5 6) (7 8 9))
  ((((let X) (let Y) (let Z)) ...)
   (vector X Y Z))
  (else #f))
⇒ (#(1 2 3) #(4 5 6) #(7 8 9))

(match '((1 2 3)
         (4 5 6)
         (7 8 9))
  ((((let X) (let Y) ...) ...)
   (vector X Y))
  (else #f))
⇒ ((#(1 2) #(1 3))
    (#(4 5) #(4 6))
    (#(7 8) #(7 9)))
#(?pattern1 --- ?patternN)

Vector of N elements.

(match '#(1 2 3)
  (#(1 2 3)
   #t)
  (else #f))
⇒ #t
#(?pattern1 --- ?patternN ?patternN+1 ...)

Vector of N or more elements with terminating ellipsis; each element of remainder must match ?patternN+1. The body is evaluated once for every element matched by the pattern before the ellipsis and the results are returned in a list.

(match '#(1 1 1)
  (#(1 ...)       #t)
  (else           #f))
⇒ (#t #t #t)
(and ?pattern ---)

Matches if each ?pattern matches the input expression. The empty and succeeds.

(match 123
  ((and (apply fixnum?) (apply positive?))
   #t)
  (else #f))
⇒ #t

(match 123
  ((and (apply fixnum?) (let X))
   X)
  (else #f))
⇒ 123

(match 123
  ((and (let X) X)
   X)
  (else #f))
⇒ 123
(or ?pattern ---)

Matches if at least one ?pattern matches the input expression. The empty or fails.

(match 1
  ((or 1 2)
   #t)
  (else #f))
⇒ #t

(match 1
  ((or (apply fixnum?) (apply bignum?))
   #t)
  (else #f))
⇒ #t
(not ?pattern)

Matches if the subpattern ?pattern does not match the input expression. The empty not fails. The empty not pattern is a syntax error; the not pattern with multiple subpatterns is a syntax error.

(match 9
  ((not 1)
   #t)
  (else #f))
⇒ #t

(match "ciao"
  ((not (apply fixnum?))
   #t)
  (else #f))
⇒ #t
(apply ?pred ---)

Each ?pred subpattern must be an expression; every time this pattern is matched against an input expression: ?pred is evaluated; the value returned by ?pred must be a predicate function. This pattern matches if all the predicate functions return true when applied to the input expression; the empty apply pattern is a syntax error.

(match 1
  ((apply fixnum? positive?)
   #t)
  (else #f))
⇒ #t

(match 1
  ((apply (lambda (x)
            (and (fixnum?   x)
                 (positive? x))))
   #t)
  (else #f))
⇒ #t
(eval ?expr)

The subpattern ?expr must be expression; every time this pattern is matched against an input expression: ?expr is evaluated. This pattern matches if the result of ?expr is true. The empty eval pattern is a syntax error; the eval pattern with multiple subpatterns is a syntax error.

(match 1
  ((eval #t)
   #t)
  (else #f))
⇒ #t

(match 1
  ((eval #f)    #\A)
  (else         #f))
⇒ #t

(match #t
  ((and (let X) (eval X))
   #t)
  (else #f))
⇒ #t

(match #f
  ((and (let X) (eval X))
   #t)
  (else #f))
⇒ #f

(match '(1 2)
  (((let X) (eval X)) ;ignores 2, but consumes it
   X)
  (else #f))
⇒ 1

(match '(1 2 3)
  (((let X) (eval X) (let Y)) ;ignores 2, but consumes it
   (vector X Y))
  (else #f))
⇒ #(1 3)

When the escape identifier is present, it is bound to a thunk to be evaluated to jump to matching the next pattern or to the “no match” error.

(match '(1 2 3)
  ((1 2 3)
   (=> escape)
   #t)
  (else #f))
⇒ #t

(match '(1 2 0)
  ((1 2 3)
   (=> escape)
   #t)
  (else #f))
⇒ #f

(match '(1 2 3)
  ((1 2 3)
   (=> escape)
   (escape))
  (else #f))
⇒ #f

(match '(1 2 3)
  ((1 2 3)
   (=> escape)
   (escape))
  ((1 2 3)
   #t)
  (else #f))
⇒ #t

(match '(1 2 3)
  ((1 2 3)
   (=> escape)
   (escape)))
error→ &error

Up: simple-match   [Index]