-
Notifications
You must be signed in to change notification settings - Fork 22
Various Patterns
Trivia maintains a full compatibility with Optima. If you are already familier with Optima, there is no need to understand anything new, other than the additional patterns introduced in Trivia.
As the baseline, this page describe the syntax of macro match
and its variants.
In the following sections, I briefly summarize what kind of patterns are available in these matcher macros.
This section contains standard, object-accessing patterns that are most commonly used.
- Syntax
- cons cdr car
cons
checks if the object is of type cons
, and then matches its
subpatterns with car
and cdr
of that cons cell.
(match '(1 2 3)
((cons x y)
(print x)
(print y)))
;; |-> 1
;; |-> (2 3)
- Syntax
- list &rest subpatterns
list* &rest subpatterns
Both patterns checks if the object is of type list
, has the same length and then matches the contents to the subpatterns. list*
also checks the elements against the subpatterns, however the
last pattern is matched against nthcdr
of the list. Thus, the code below
returns 3
.
(match '(1 2 . 3)
((list* _ _ x)
x))
Both patterns can be derived from cons
pattern. See also: ./defpattern
- Syntax
- vector &rest subpatterns
vector* &rest subpatterns
vector
checks if the object is a vector, if the lengths are the same, and
if the contents matches against each subpatterns. vector*
is similar, but
called a soft-match variant that allows if the length is
larger-than-equal to the length of subpatterns.
(match #(1 2 3)
((vector _ x _)
x))
;; -> 2
(match #(1 2 3 4)
((vector _ x _)
x))
;; -> NIL : does not match
(match #(1 2 3 4)
((vector* _ x _)
x))
;; -> 2 : soft match.
There are several specialized subpatterns for vector/vector*. Using these variants properly will results in faster code.
<vector-pattern> : vector | simple-vector
bit-vector | simple-bit-vector
string | simple-string
base-string | simple-base-string | sequence
(<vector-pattern> &rest subpatterns)
- Syntax
- class type &rest slot-descriptions
structure type &rest slot-descriptions
- slot-descriptions
- either of the following:
- make-instance style plist :
{keyword subpattern}*
- with-slots style :
(slot-name subpattern)*
- names as the variables :
slot-name*
- make-instance style plist :
structure
pattern is just a synonym to the class
pattern.
We just post an example for each of three style here.
(defstruct foo bar baz)
(defvar *x* (make-foo :bar 0 :baz 1)
(match *x*
((foo :bar a :baz b) ;; make-instance style
(values a b))
((foo (bar a) (baz b)) ;; with-slots style
(values a b))
((foo bar baz) ;; slot name
(values bar baz)))
- Syntax
- type type
satisfies predicate
- type
- type specifier, not evaluated.
- predicate
- a name of a boolean function of 1 argument, not evaluated.
type
pattern matches if the object is of type. satisfies
matches if
the predicate returns true for the object. lambda
form is acceptable.
- Syntax
- assoc item subpattern &key key test
property key subpattern &optional default
All these patterns first checks if the pattern is a list. If that is
satisfied, it then obtain the contents with (cdr (assoc item X key test))
(assoc pattern) or (getf key X)
(property pattern) where X is bound the container. The value
obtained by these accessors is then matched against subpattern.
Two patterns are derived from these patterns.
- Syntax
- alist &rest args
plist &rest args
alist
and plist
patterns expand into a collection of assoc
and
property
patterns, respectively, connected by an and
pattern.
- Syntax
- and &rest subpattterns
or &rest subpattterns
They matches when all/some of the subpatterns matches against the element. For example,
(match x
((or (list 1 a)
(cons a 3))
a))
matches against both (1 2)
and (4 . 3)
and returns 2 and
4, respectively. Also,
(match x
((and (list 1 _)
(list _ 2))
t))
is same as below.
(match x
((list 1 2)
t))
- Syntax
- not subpattern
It does not match when subpattern matches. The variables used in subpattern is not visible in the body.
- Syntax
- guard subpattern1 test-form {generator-form subpattern2}*
- test-form
- a predicate form, evaluated.
- generator-form
- a form that produce a value, which are then matched against the next subpattern2.
The object is first matched against subpattern1. If that fails, whole clause declines the matching. Otherwize, test-form is evaluated. When the result is true, then each of generator-form is evaluated and matched against corresponding subpattern2.
Example:
(match (list 2 5)
((guard (list x y) ; subpattern
(= 10 (* x y)) ; test-form
(- x y) (satisfies evenp)) ; generator1, subpattern1
t))
;; --> nil, since (- x y) == 3 does not satisfies evenp
This section contains patterns that has specific roles in itself.
- Syntax
- place subpattern
The subpattern is accessed by symbol-macrolet
instead of let
.
Example:
(defvar *x* (list 0 1))
(match *x*
((list (place x) y)
(setf x :success)
(setf y :fail)))
(print *x*)
;; --> (:SUCCESS 1)
- Syntax
- <> pattern value &optional var
The current matching value is bound to var
.
The result of evaluating value
using var
is then matched against pattern
.
var
is optional and can be omitted when value
is a constant and does not need the current matching value.
This is important when you write a defpattern
that has a default
value. Consider writing a pattern that matches against both of 'string
and '(string *)
and has a subpattern length
. length should be bound to
'*
even when the input is 'string
. With <>
pattern, it can be
implemented as below.
(defpattern string-type-specifier (length)
`(or (list 'string ,length)
(and 'string (<> ,length '*))))
Just want to access an element? It’s time to use access
pattern:
- Syntax
- access #’accessor subpattern
- Syntax
- access ‘accessor subpattern
- accessor
- a function name.
The object is not checked. The value of funcall
ing the current object is
matched against subpattern.
Example:
(match '((1 2 (3 4)) 5 (6))
((access #'flatten (list* _ _ 3 _))))
For a quickstart, go to the Basics section. Below is for the people already familiar with Optima.