(destructuring-bind
(a b (c d ()) . e)
foo
(bar a b c d e))
You'd write
(letm
(list* a b (list c d ()) e)
foo
(bar a b c d e))
Use these macros in your code:
There are others.
ifmatch
Patterns are lisp forms. Symbol in patterns match anything creating a binding to what they match, except * or _ will match anything but are not bound. Literals are matched using eq.
The core pattern matching forms are look like the forms for consing up things and match what otherwise they would create: list, list*, values, cons, and vector. Quite concise is that for most common lisp implementations you may use back-quoted forms.
(match msg
(`(+ ,a ,b) (+ a b))
(`(- ,a ,b) (- a b))
(`(- ,a) (- a b)))
Two forms slot*, accessor* allow you to match CLOS objects using the slot-names or the accessors respectively. By example:
Finally a few pattern forms provide for special cases: and, or, of-type, like-when.
(defun window-hieght (window)
(letm (slot* (top a) (bottom b)) window
(- bottom top)))
Some samples pulled from a test case:
(ifmatch (like-when (cons x y) (eql x y)) '(2 . 2) x) ==> 2
(ifmatch (and (cons x y) (when (eql x y))) '(2 . 2) x) ==> 2
(ifmatch (and (cons a 1) (cons 2 b)) '(2 . 1) (list a b)) ==> (2 1)
(ifmatch (list a b) '(1 2) (list b a)) ==> (2 1)
(ifmatch (list* a b c) '(1 2 3 4) (list a b c)) ==> (1 2 (3 4))
(ifmatch (and x (cons (of-type integer) *)) '(2) x) => (2)
(defun my-length (x)
(ematch x
((cons * tail) (1+ (my-length tail)))
('nil 0))
(my-length '(1 2 3)) ==> 3
(ifmatch (cons * (cons x y)) '(1 (2 3) 4) (list x y)) ==> ((2 3) (4))
Finally, from the source code:
This is my attempt at a pattern matcher.
Semantic Design goals:
Implementation goals:
Lisp2 style means that instead of writing (destructuring-bind (a b (c d ()) . e) foo (bar a b c d e)) You'd write (match1 (list* a b (list c d 'nil) e) foo (bar a b c d e)) This might look heavier, but then, the fact that the head of a pattern is a designator for an arbitrary pattern instead of having patterns always be lists except for possible "magic" values like &rest and other keywords allows patterns to be clearer, and *extensible*. Thus you can trust that any symbol in head position is a pattern name, while any symbol in parameter position is a variable name, except if it is a special symbol, or if the head is a pattern macro, in which case it controls the meaning of the parameters.
The only predefined special symbol is _ that matches everything. I used to have T match anything (top) and NIL match nothing (bottom), but nobody liked it, so instead they are considered (together with keywords) as literals that match the constants T and NIL. Predefine functional patterns are CONS, LIST, LIST*, VECTOR, that match corresponding objects with a known arity. Predefined macro patterns are QUOTE, VALUE, LIKE-WHEN, AND, WHEN, OF-TYPE, SLOT*, ACCESSOR*, that respectively match a literal constant, the value of an expression, a pattern with a guard condition, the conjunction of several patterns, just a guard condition, any value of given type, any object with slots as specified, and object with accessors as specified. In fare-clos, it is also possible to match against an INSTANCE of a class with slots specified by initargs.
IFMATCH tries to match a pattern with an expression, and conditionally executes either the success form in a properly extended lexical environment, or the failure form in the original lexical environment, depending on whether the match succeeded (with freshly bound variables) or not. MATCH (that I won't rename to COND-MATCH) tries to match a given expression with several patterns, and executes the body of the matching clause if found. EMATCH is like MATCH except that when no match is found, it raises an error instead of returning NIL.
With this paradigm, matching patterns are thus dual from normal forms. I like to think of all forms as patterns, with some patterns being in "deconstruction position" (left-hand side of a match clause), and other patterns being in "construction position" (right-hand side of a match clause). Although the current implementation follows Erlang (or ML-like) semantics for matching, this paradigm can generalize to non-deterministic settings, where you'd obtain something much like Mercury, unifying functional and logic programming -- however, I haven't even attempted to implement non-determinism (maybe this could be done using Screamer).
NB: Actually, I had first thought about this pattern-matcher when I was more of a Lisp1 fan, and the fact that Lisp2 was much more natural for the pattern matcher finished to turn me into a Lisp2 fan.
This page is linked from: fare-matcher
CLiki pages can be edited by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively