-
Notifications
You must be signed in to change notification settings - Fork 22
Level 1 Patterns
Level 1 matchers/patterns are the foundations of all level 2 patterns and optimizers. It provides only 2 patterns. Their roles are primitive and thus its compiler can be dead simple & clean.
All level 2 patterns are expanded into level 1 patterns with defpattern. Likewise, All level 2 matcher macros are expanded into level 1 matcher macros.
(guard1 symbol test-form {generator-form subpattern}*)
- It binds the current matching value to
symbol
withlet
and conduct checking on it withtest-form
. It the test fails, it goes to the next pattern. - if the test succeeds, each
generator-form
is evaluated and its value is matched against the correspondingsubpattern
. - Unlike
guard
pattern in Optima,guard1
pattern does not allow subpatterns insymbol
(and is thus more primitive). Subpatterns are only permitted in{generator-form subpattern}*
part. Oneguard1
pattern corresponds to exactly one type checking. - While
symbol
does not contain subpatterns, it has an additional functionality:symbol
may contain additional lexical information. For details see the next section. - Level-1 patterns should be canonical. That is, there should be no forward-referenced symbols.
Thus, compilation of guard1
is equivalent to just building a
form consisting of if
and let
binding. match1
assumes the
matching tree is already valid and optimized.
Example:
(match1 '(1 2)
((guard1 temp (consp temp)
(car temp) (guard1 a t)
(cadr temp) (guard1 b t))
(vector a b)))
;; --> #(1 2)
Note that, since even variable patterns are missing in Level 1,
one should use (guard1 a t)
to bind the value generated by (car
temp)
. It produces a code like below.
(LET ((#:WHAT1862 '(1 2)))
(BLOCK NIL
(LET ((TEMP #:WHAT1862))
(WHEN (CONSP TEMP)
(LET ((A (CAR TEMP)))
(WHEN T
(LET ((B (CADR TEMP)))
(WHEN T (RETURN (LOCALLY (VECTOR A B)))))))))))
As noted earlier, guard1
may contain additional lexical declaration information within symbol
. While the normal syntax of guard1 is as follows:
(guard1 symbol test-form {generator-form subpattern}*)
the extended guard1 syntax is:
(guard1 (sym &key
(type t)
(binder 'let)
(ignorable (if (symbol-package sym) nil t))
dynamic-extent
special
&allow-other-keys)
test-form {generator-form subpattern}*)
- type
- a type specifier. It is added to the declaration after
let
. - binder
- either a symbol `let`, `symbol-macrolet`, `progv`. The resulting binding is generated with these special forms. For example, with `symbol-macrolet`, then the symbol is bound with symbol-macrolet and the accessor becomes setf-able.
- ignorable
- If non-nil,
symbol
is declared to beignorable
. Default value isT
whensymbol
is an apparently uninterned symbol, andNIL
otherwise. - dynamic-extent
- If non-nil, it adds `dynamic-extent` declaration.
- special
- If non-nil, it adds `special` declaration.
Note that type
does not affect the pattern optimizer nor the test form. The declaration is added only to the conditional branch where the test form is evaluated to be true.
(or1 subpattens*)
Or1 has an important role called consistency check, of checking if the set of variables in each branch is set-equal to each other. If two subpatterns have the different sets of variables, missing variables are assigned NIL.
(defun test (x)
(match x
;; using level2 cons/vector pattern for convenience
((or1 (cons a b)
(vector a c)) (values a b c))))
(test '(1 . 2)) ;; --> 1, 2, nil
(test #(1 2)) ;; --> 1, nil, 2
This behavior can be changed by setting *or-pattern-allow-unshared-variables*
to NIL
, in which case variable inconsitency will signal an assertion error of type or1-pattern-inconsistency
, with (repair-pattern subpattern)
restart. You may fix and replace the subpattern by calling this handler with a new pattern.
When a symbol is declared to be ignorable by guard1
, it is not accounted for consistency check.
For a quickstart, go to the Basics section. Below is for the people already familiar with Optima.