This is the mail archive of the
kawa@sourceware.org
mailing list for the Kawa project.
match form as a generalization of case
I checked into the invoke branch a new 'match' form.
(Actually, it was there before, but was broken.)
I also checked some pattern extension to make match more useful, and
documentation.
If you want to try it out without re-building form git,
you can try this:
http://ftp.gnu.org/gnu/kawa/kawa-2.91_invoke-20170121.zip
That zip file includes the documentation, which you can browse
with the command:
kawa-2.91_invoke/bin/kawa --browse-manual
Here are the highlights. Note also that lambda and let forms
both take PATTERNs now.
-- Syntax: match MATCH-KEY EXPRESSION MATCH-CLAUSE^{+}
The ‘match’ form is a generalization of ‘case’ using PATTERNs,
MATCH-KEY ::= EXPRESSION
MATCH-CLAUSE ::=
‘(’ PATTERN [GUARD] BODY ‘)’
The MATCH-KEY is evaluated, Then the MATCH-CLAUSEs are tried in
order. The first MATCH-CLAUSE whose PATTERN matches (and the
GUARD, if any, is true), is selected, and the corresponding BODY
evaluated. It is an error if no MATCH-CLAUSE matches.
(match value
(0 (found-zero))
(x #if (> x 0) (found-positive x))
(x #if (< x 0) (found-negative x))
(x::symbol (found-symbol x))
(_ (found-other)))
One ‘case’ feature is not (yet) directly supported by ‘match’:
Matching against a list of values. However, this is easy to
simulate using a guard using ‘memq’, ‘memv’, or ‘member’:
;; compare similar example under case
(match (car '(c d))
(x #!if (memv x '(a e i o u)) ’vowel)
(x #!if (memv x '(w y)) ’semivowel)
(x x))
8.3.1 Patterns
--------------
The usual way to bind variables is to match an incoming value against a
“pattern”. The pattern contains variables that are bound to some value
derived from the value.
(! [x::double y::double] (some-expression))
In the above example, the pattern ‘[x::double y::double]’ is matched
against the incoming value that results from evaluating
‘(some-expression)’. That value is required to be a two-element
sequence. Then the sub-pattern ‘x::double’ is matched against element 0
of the sequence, which means it is coerced to a ‘double’ and then the
coerced value is matched against the sub-pattern ‘x’ (which trivially
succeeds). Similarly, ‘y::double’ is matched against element 1.
The syntax of patterns is a work-in-progress. (The focus until now has
been in designing and implementing how patterns work in general, rather
than the details of the pattern syntax.)
PATTERN ::= IDENTIFIER
| ‘_’
| PATTERN-LITERAL
| ‘’’DATUM
| PATTERN ‘::’ TYPE
| ‘[’ LPATTERN^{*} ‘]’
LPATTERN ::= PATTERN
| ‘@’ PATTERN
| PATTERN ‘...’
| GUARD
PATTERN-LITERAL ::=
BOOLEAN | number | CHARACTER | STRING
GUARD ::= ‘#!if’ EXPRESSION
This is how the specific patterns work:
IDENTIFIER
This is the simplest and most common form of pattern. The
IDENTIFIER is bound to a new variable that is initialized to the
incoming value.
‘_’
This pattern just discards the incoming value. It is equivalent to
a unique otherwise-unused IDENTIFIER.
PATTERN-LITERAL
Matches if the value is ‘equal?’ to the PATTERN-LITERAL.
‘’’DATUM
Matches if the value is ‘equal?’ to the quoted DATUM.
PATTERN ‘::’ TYPE
The incoming value is coerced to a value of the specified TYPE, and
then the coerced value is matched against the sub-PATTERN. Most
commonly the sub-PATTERN is a plain IDENTIFIER, so the latter match
is trivial.
‘[’ LPATTERN^{*} ‘]’
The incoming value must be a sequence (a list, vector or similar).
In the case where each sub-pattern is a plain PATTERN, then the
number of sub-patterns must match the size of the sequence, and
each sub-pattern is matched against the corresponding element of
the sequence. More generally, each sub-pattern may match zero or
more consequtive elements of the incoming sequence.
‘#!if’ EXPRESSION
No incoming value is used. Instead the EXPRESSION is evaluated.
If the result is true, matching succeeds (so far); otherwise the
match fails. This form is called a “guard”
(https://en.wikipedia.org/wiki/Guard_(computer_science)).
--
--Per Bothner
per@bothner.com http://per.bothner.com/